11.1. Příkaz CALL Formát: - - - - | | položka | | | | speciální-index | | | | * {položka | sp.index} | | | | ** {num.položka|UI|SI} | | | | *** {num.položka|UI|SI} | | | | literál | | | | * alfanumerický-literál | | | | {* | ** | ***} num.lit. | | CALL 'externí-jméno' | USING < jméno-souboru >...| | | jméno-třídicího-souboru | | | | (externí-jméno) | | | | * (externí-jméno) | | | | jméno-komunikační-obl. | | | | / položka | | | | < {položka | sp.index} | | | | << {položka | sp.index} | | - - - - Ve formátu "UI" znamená UI-položku (tzn. položku s USAGE INDEX) a "SI" znamená speciální-index. Funkce: Příkaz CALL způsobí předání řízení a případně též argumentů z cobolského programu na vstupní bod ležící v druhém programu. Externí jméno uvedené za slovem CALL (což musí být posloupnost nejvýše 31 malých i velkých písmen, číslic a podtrhovátek začínající písmenem nebo podtrhovátkem a zapsaná v apostrofech) musí být jménem tohoto vstupního bodu. (Malá písmena v externím jméně nejsou měněna na velká.) Jak čtenář zajisté ví, překladač překládá cobolský zdrojový program do programu v jazyku C. Příkaz CALL bude přeložen voláním funkce, jejíž jméno se shoduje s externím jménem uvedeným za slovem CALL (samozřejmě bez apostrofů), která nevrací žádnou hodnotu (je typu "void") a jíž jsou předávány argumenty odpovídající argumentům uvedeným v příkazu CALL za slovem USING (viz dále). Do C-programu není zařazována žádná "deklarace" této funkce; argumenty budou tedy vyvolané funkci předávány ve svém "přirozeném" typu. (Pokud by si uživatel přál, aby byly předávané argumenty přetypovány, musel by sám zařadit pomocí příkazu UFD do C-programu vhodnou deklaraci volané funkce.) Spojovací program pak při zpracovávání našeho programu najde v některém jiném programu spojovaném současně s naším programem (případně v programu zařazeném pomocí tzv. autolinku) funkci tohoto jména a její adresu dá k dispozici našemu programu; právě tuto funkci pak příkaz CALL volá dle obvyklých konvencí jazyka C. Registrové a jiné konvence při předávání řízení a argumentů z hlediska strojových instrukcí nejsou v této příručce popisovány, neboť jsou závislé na použitém počítači, operačním systému a překladači jazyka C. Je-li program, v němž spojovací program nalezl stejnojmennou funkce, napsán v jazyku C, musí se jednat o definici funkce (s "tělem"). Pokud tato funkci vrací nějakou hodnotu, bude tato hodnota po návratu do volajícího cobolského programu ignorována. Je-li zmíněný program napsán v COBOLu, musí být uvedeno jméno přesně shodné s externím jménem z příkazu CALL jako jméno programu v paragrafu PROGRAM-ID nebo jako externí jméno z některého příkazu ENTRY. Zmíněný program může být ovšem napsán i v kterémkoliv jiném programovacím jazyce, jenž umožňuje definovat funkci volatelnou dle konvencí jazyka C (stačí funkce typu "void" nevracející žádnou hodnotu). Za podmínek definovaných použitým spojovacím programem nemusí uživatel explicitně žádat o připojení programu obsahujícího volanou funkci, neboť spojovací program jej dovede vyhledat a připojit automaticky (pomocí tzv. autolinku). Jak vyplývá z výše uvedeného a z konvencí jazyka C, vyvolaná funkce nedostává informaci o počtu předávaných argumentů ani nedostává nějak speciálně "označen" poslední předávaný argument. Pokud není počet argumentů pevně určen, měla by být vyvolaná funkce schopna jej zjistit z hodnot uvedených argumentů (např. že by první argument určoval celkový počet argumentů nebo že by se za poslední významný argument ještě přidal speciální koncový argument apod.). Příklad: Příkaz CALL 'Petr' se přeloží C-příkazem "(void)Petr();". Příkaz CALL 'pavel' USING A B C se přeloží C-příkazem "(void)pavel(A1,B1,C1);", kde výrazy C-jazyka A1, B1 a C1 odpovídají argumentům A, B a C uvedeným za USING. Nechceme-li vyvolanému programu předávat argumenty, použijeme formát příkazu CALL bez klauzule USING (např. CALL 'ABC'); v tom případě nebude ani volání funkce, jež vznikne překladem příkazu CALL do jazyka C, obsahovat argumenty. Chceme-li vyvolanému programu předávat argumenty, použijeme formát příkazu CALL s klauzulí USING. V tom případě bude volání funkce, jež vznikne překladem příkazu CALL do jazyka C, obsahovat právě tolik argumentů, kolik je uvedeno argumentů za slovem USING. Budou to výrazy jazyka C odpovídající argumentům uvedeným za slovem USING (dle pravidel popsaných dále, většinou se jedná o ukazatel na první byte argumentu) a jejich pořadí ve volání funkce bude shodné s pořadím odpovídajících argumentů za slovem CALL. Argumenty uvedené za USING mohou být následujících typů: A) Položka Smí být jakéhokoliv typu, smí mít kvalifikaci i indexy. Může být popsána v kterékoliv sekci; u položek z FILE SECTION nebo z LINKAGE SECTION se ovšem vyžaduje, aby v době provádění příkazu CALL měly přidělen skutečný úsek paměti. Odpovídající argument ve volání funkce v cílovém C-programu bude ukazatel na první byte úseku paměti přiděleného položce (tedy výraz typu "unsigned char*", např. "W+k" resp. "F[n].r01+k" resp. "L[n]+k", kde "n" je celé číslo a "k" zastupuje celé číslo nebo (v případě proměnných indexů nebo proměnné adresy) proměnný výraz typu "short" nebo "long"). Poznámka: Jako argument v příkazu CALL lze uvést i libovolnou položku definovanou překladačem (viz 4.11.). V případě položek CURRENT-DATE (TODAYS-DATE), TIME-OF-DAY, COM-REG a NSTD-REELS se před vyvoláním funkce vytvoří v pracovní paměti volatele příslušná hodnota odpovídající implicitnímu popisu uvedené položky a volané funkci se předá ukazatel na první byte této hodnoty. Před výše vyjmenovanými položkami definovanými překladačem nesmí být uvedeno * ani ** ani ***. Všechny ostatní položky definované překladačem (TALLY, WHEN-COMPILED, NSTD-REELS a položky pro Generátor sestav a pro třídění) jsou zcela normálními položkami, pro které platí stejná pravidla jako pro položky definované uživatelem (včetně možnosti uvedení * resp. ** resp. ***). B) Speciální-index Smí mít uvedenu kvalifikaci. Odpovídající argument ve volání funkce bude ukazatel na "long" přidělený speciálnímu indexu pro uchování jeho hodnoty (tedy výraz typu "long*", např. při osmém speciálním indexu to bude "&S[7]"). C) Argumenty "* položka", "** položka" a "*** položka" Jak bylo řečeno výše, při uvedení položky jakožto argumentu za USING se volané funkci předává ukazatel na první byte úseku paměti přiděleného této položce, tzn. adresa této položky. Naproti tomu při uvedení argumentu "* položka" nebo "** položka" nebo "*** položka" (srv. též příkaz UFO) se volané funkci předává hodnota této položky, a to u numerických položek při * převedená do typu "short", při ** převedená do typu "long" a při *** převedená do typu "double" (pravidla jsou jiná než u příkazu UFO!). Namísto položky lze uvést i speciální index. 1) Jednu hvězdičku ("* položka") lze uvést před libovolnou položkou (s výjimkou skupinových položek s proměnnou délkou) anebo před speciálním indexem. Argumentem předávaným volané funkci bude takovýto výraz jazyka C: a) V případě jednobytové skupinové nebo alfanumerické položky se předává hodnota tohoto jediného bytu, tedy výraz typu "unsigned char"; např. *(W+58). b) V případě skupinové, alfanumerické nebo alfanumerické editované položky o pevné délce n > 1 se předává struktura zahrnující celou tuto položku; např. *(struct {char x[n];}*)(W+58). c) V případě numerické položka, položky s USAGE INDEX nebo speciálního indexu se předává hodnota této položky převedená do typu "short"; např. *(short*)(W+58) u dvoubytové binární položky, (short)*(long*)(W+58) u čtyřbytové binární položky, icbditos(W+58,3) resp. (short)icbditol(W+58,7) resp. (short)(icbditod(W+58,8)/1e3) u rozpakované položky, (short)*(double*)(W+58) u exponenciální dlouhé položky apod. 2) Dvě hvězdičky ("** položka") lze uvést pouze před numerickou položkou, UI-položkou a před speciálním indexem. Předává se hodnota této položky převedená do typu "long"; např. (long)*(short*)(W+58) u dvoubytové binární položky, *(long*)(W+58) u čtyřbytové binární položky nebo u UI-položky, S[3] u speciálního indexu, icbpatol(W+58,2) resp. (long)(icbpatod(W+58,2)/1e1) u pakované položky, (long)(icbezout(W+58)/1e12) u exponenciální znakové položky apod. 3) Tři hvězdičky ("*** položka") lze uvést pouze před numerickou položkou, UI-položkou a před speciálním indexem. Předává se hodnota této položky převedená do typu "double"; např. (double)*(short*)(W+58) u binární položky, icbditod(W+58,3) resp. (icbditod(W+58,3)/1e1) u rozpakované položky, (double)*(float*)(W+58) u exponenciální krátké položky, *(double*)(W+58) u exponenciální dlouhé položky apod. Poznámka: Pokud chce uživatel při položce s PIC 99V99 a s hodnotou 12.34 předávat hodnotu 1234, musí si položku redefinovat pomocí položky s PIC 9999 a tuto pak uvést (s vhodným počtem hvězdiček) jako argument za USING. Jinak bude předávána při * nebo ** hodnota 12 převedená do typu "short" nebo "long" a při *** hodnota 12.34 převedená do typu "double". Poznámka: Nechá-li uživatel převádět exponenciální položku nebo položku s vyšším počtem dekadických řádů do typu "short" nebo "long", měl by zajistit, aby se hodnota této položky do "shortu" resp. "longu" vešla (tzn. aby byla mezi -32768 a +32767 při * resp. mezi -2147483648 a +2147483647 při **), jinak bude předávaná hodnota nedefinovaná. Poznámka: Uvedení jedné, dvou nebo tří hvězdiček není otázkou libovůle; volající program musí předávat argumenty v takovém typu, v jakém je vyvolaná funkce očekává. Uživatel tedy musí zjistit v definici volané funkce typy jednotlivých formálních parametrů a tomu přizpůsobit typy skutečných parametrů neboli zápis argumentů uvedených za USING. Příklad: Chceme-li vyvolat funkci jaroslav a jako argumenty jí předat hodnotu položky ALFA převedenou do typu "long" a hodnotu položky BETA převedenou do typu "double", píšeme CALL 'jaroslav' USING **ALFA ***BETA. D) Literál Odpovídající argument ve volání funkce bude řetězec ("...") obsahující tento literál upravený dále popsaným způsobem. Případné netisknutelné znaky, které vznikají obzvláště v případě alfanumerického literálu v hexadecimálním zápisu a v případě numerického literálu, budou vyjádřeny nouzovými sekvencemi \nnn. Překladač jazyka C uloží vnitřek tohoto řetězce (tzn. původní literál v upraveném tvaru) do statické paměťové oblasti a volané funkci předá ukazatel na první byte uloženého upraveného literálu (tedy konstantní hodnotu typu "char*"). Není přípustné uvést místo literálu jako argument příkazu CALL ani figurativní konstantu ani ALL-klauzuli. - V případě alfanumerického literálu bude zahrnut do řetězcových uvozovek a tedy uložen do statické paměťové oblasti jeho "vnitřek" bez ohraničujících apostrofů v nezměněném obsahu i délce. (Např. příkaz CALL 'PETR' USING 'Praha' #00FF0A# bude přeložen voláním funkce (void)PETR("Praha","\0\377\10"), předá tedy vyvolané funkci dvě adresy znakových polí.) - Numerický literál bude upraven takto: Desetinná tečka a exponentová část se vynechají (uživatel je tedy může uvést pouze jako poznámky, literál se vždy zpracovává jako celé číslo s případným znaménkem). Literál se převede do pakovaného (!) tvaru, přičemž levostranné nuly se neodstraňují (literál s m ciframi bude mít tedy po spakování v řetězci a tedy i ve statické paměťové oblasti délku rovnou celočíselné části z čísla m/2 + 1). Nemá-li literál uvedeno žádné znaménko nebo má-li uvedeno znaménko +, bude znaménkový půlbyte (tj. pravý půlbyte posledního bytu) upraveného literálu vždy obsahovat hexadecimální 3. Má-li literál uvedeno znaménko -, bude znaménkový půlbyte upraveného literálu obsahovat hexadecimální 4. (Převádění numerického literálu do pakovaného tvaru bylo nutno dodržet kvůli kompatibilitě s COBOLem MOS a COBOLem DOS-3. V COBOLu MX, v němž nelze počítat s existencí strojových instrukcí pro pakované operandy, je pakovaný formát značně neefektivní. Pokud tedy není uživatel nucen kvůli kompatibilitě dodržet pakovaný tvar, doporučujeme uvádět raději jako argument binární nebo exponenciální položku s požadovanou hodnotou dosazenou klauzulí VALUE nebo předávat přímo hodnotu numerického literálu předřazením * resp. ** resp. *** před numerický literál.) literál ve zdrojovém upravený literál ve statické programu (znakově) paměťové oblasti (hexadecimálně) ------------------------------------------------------- 'A1B+' 4131422B #00FF0A# 00FF0A 14 0143 000256 00002563 +324 3243 -3.240 032404 -0032.000 00320004 7.5E-12 0753 Použití literálu (zvláště numerického) jako argumentu příkazu CALL vyžaduje velkou opatrnost a může být proto doporučeno jen zkušeným programátorům. E) Argument "* alfanumerický-literál" Před alfanumerickým literálem je přípustné (obdobně jako před alfanumerickou položkou) uvést jednu hvězdičku. a) V případě jednoznakového alfanumerického literálu se předává znaková konstanta tvořená tímto jediným znakem, tzn. výraz typu "char"; např. příkaz CALL 'PETR' USING *'T' by se přeložil jako (void)PETR('T'). b) V případě víceznakového alfanumerického literálu (o délce n > 1) se předává struktura zahrnující celý tento literál; např. příkaz CALL 'PETR' USING *'PRAHA' by se přeložil jako (void)PETR(*(struct {char x[5];}*)Jm), kde m je vhodné celé číslo zajišťující jednoznačnost jména Jm a proměnná Jm je definována pomocí "static char Jm[5]="PRAHA";". F) Argumenty "* n.literál", "** n.literál" a "*** n.literál" Před numerickým literálem je přípustné (obdobně jako před numerickou položkou) uvést jednu, dvě nebo tři hvězdičky, jejichž rozdílnost se však projeví pouze u celočíselného numerického literálu (tzn. u celého čísla opatřeného případně znaménkem -). Volané funkci bude předávána vždy hodnota uvedeného numerického literálu, a to převedená do typu "short" (při *, pouze ovšem u celočíselného numerického literálu s hodnotou mezi -32768 a +32767) resp. do typu "long" (při **, pouze ovšem u celočíselného numerického literálu; dále též při * u celočíselného numerického literálu s hodnotou menší než -32768 nebo větší než +32767; hodnota literálu ovšem musí být v obou případech mezi -2147483648 a +2147483647) resp. do typu "double" (vždy při ***; dále též při * nebo ** u neceločíselného numerického literálu). Příklad: Příkaz CALL 'Josef' USING *56 **56 ***56 *5000000 **5000000 ***5000000 *1.5 **1.5 ***1.5 bude přeložen takto: (void)Josef(56,56L,56.,5000000,5000000L,5000000.,15e-1, 15e-1,15e-1); G) Jméno-souboru a jméno-třídicího-souboru Každý soubor (FD) i třídicí soubor (SD) je v cílovém C-programu representován strukturou typu "struct sdtf", kde deklarace struktury sdtf je includována do cílového C-programu a pilný programátor ji může najít v jednom z includovaných souborů. Odpovídající argument ve volání funkce bude ukazatel na tuto strukturu (tedy výraz typu "struct sdtf*", např. při souboru popsaném osmou klauzulí FD/SD ve FILE SECTION to bude "&F[7]"). Ve vyvolané funkci je pak možné provádět s tímto souborem nějaké nestandardní akce, něco změnit nebo testovat v přidělené struktuře atd. Pokud však programátor v této struktuře něco změní bez konzultace s autory překladače, zodpovídá sám za případný další chybný výpočet. H) (externí-jméno) Lze uvést jakékoliv slovo vyhovující pravidlům z 1.8. (posloupnost nejvýše 31 malých i velkých písmen, číslic a podtrhovátek začínající písmenem nebo podtrhovátkem; malá písmena nejsou překladačem měněna na velká) uzavřené v kulatých závorkách. Překladač předpokládá, že uvedené jméno je jménem externí proměnné, jejíž definici (s týmž jménem) sežene spojovací program v některém jiném programu spojovaném současně s naším programem obsahujícím příkaz CALL, a jejíž adresu poskytne našemu programu (situace je zde obdobná jako u externího jména uvedeného za slovem CALL, zde se však jedná o externí proměnnou a nikoliv o externí funkci). Překladač vygeneruje do cílového C-programu deklaraci "extern char jméno;" a jakožto argument při volání funkce použije "&jméno". Vyvolané funkci bude tedy předán ukazatel na první byte proměnné pojmenované tímto jménem. (Tato externí proměnná smí být libovolného typu. Je zcela bezvýznamné, že v cílovém C-programu je tomuto jménu přidělen typ "char"; ve volané funkci lze samozřejmě odpovídajícímu formálnímu parametru přidělit jakýkoliv ukazatelový typ, tedy nejlépe takový, jenž odpovídá skutečnému typu naší externí proměnné. Uživatel ovšem nesmí pomocí příkazu UFD zařadit do cílového C-programu jinou deklaraci pro totéž jméno.) Tímto způsobem tedy vyvolávající program předává pomocí příkazu CALL do vyvolaného programu adresu argumentu ležícího v některém třetím programu; může jít např. o tabulku konstant nebo položku apod. I) Argument "* (externí-jméno)" Platí zde stejná pravidla jako v předešlém případě, před levou závorkou se však zapisuje ještě hvězdička *. Překladač předpokládá, že uvedené jméno je jménem externího nebo statického objektu, jehož deklaraci zařadil sám uživatel do cílového C-programu např. explicitním příkazem UFD. Překladač proto již negeneruje do cílového C-programu žádnou deklaraci a jakožto argument při volání funkce použije "jméno" bez jakýchkoliv přídavků. Typ a hodnota argumentu předávaného funkci je výhradně záležitostí uživatele. (Jedná-li se o proměnnou, předává se její hodnota; jedná-li se o pole, předává se adresa jeho prvního prvku; jedná-li se o ukazatel, předává se jeho hodnota neboli adresa objektu; jedná-li se o funkci, předává se její adresa.) Poznámka: Pokud slovo uvedené v kulatých závorkách nesplňuje uvedená pravidla (třeba je-li uvedeno v apostrofech, načež pak může obsahovat i jiné znaky než písmena, číslice a podtrhovátka), ohlásí se upozornění 0040, avšak jméno se použije beze změny. To umožňuje předat volané funkci jakýkoliv argument; např. příkaz CALL 'PETR' USING *('*JAN') sice ohlásí upozornění 0040, avšak bude přeložen C-příkazem (void)PETR(*JAN);, čehož lze jinak v COBOLu dosáhnout jen příkazem UFO. Podobně příkaz CALL 'PETR' USING *('&josef') bude (po ohlášení upozornění 0040) přeložen C-příkazem (void)PETR(&josef), aniž by byla zařazována jakákoliv deklarace "jména" &josef (což je jediný avšak podstatný rozdíl proti příkazu CALL 'PETR' USING (josef)). J) Jméno-komunikační-oblasti Jméno komunikační oblasti (popsané klauzulí CD v COMMUNICATION SECTION) se v příkazu CALL považuje za speciální případ položky. Argument ve volání funkce bude ukazatel na první byte tzv. komunikační oblasti (její délka je 24 bytů), tj. úseku paměti přiděleného klauzuli CD (tedy výraz typu "unsigned char*", např. "W+158"). Ve vyvolané funkci je pak možné jednotlivé byty a úseky této komunikační oblasti testovat nebo měnit, případně provádět nějaké nestandardní akce atd. K) Lomítko následované jménem položky (/ položka) Položka uvedená za lomítkem musí být z LINKAGE SECTION nebo z FILE SECTION (srv. 4.4., bod 8) s číslem úrovně 01 nebo 77. (Jak je popsáno v 4.9., má každá taková položka přidělen jeden ukazatel, do něhož se v průběhu výpočtu ukládá adresa prvního bytu úseku paměti ztotožněného s touto položkou.) Odpovídající argument ve volání funkce bude adresa ukazatele přiděleného položce, tedy výraz typu "unsigned char**" s konstantní hodnotou (např. při osmé položce s číslem úrovně 01 nebo 77 z LINKAGE SECTION, nepočítáme-li položky s klauzulí REDEFINES, bude volané funkci předáván argument "&L[7]"). Uvedená položka ovšem nemusí (a většinou asi nebude) mít při provádění tohoto příkazu CALL přidělen skutečný úsek paměti. Vyvolaný program může zmíněný ukazatel naplnit adresou prvního bytu vhodného úseku paměti, čímž způsobí, že po návratu do vyvolávajícího programu za příkaz CALL (nebo po skoku na příkaz ENTRY) bude položka uvedená za lomítkem ztotožněna s tímto úsekem paměti (srv. obdobnou možnost u příkazu UFO, kde se ovšem lomítko nezapisuje, neboť se naplnění ukazatele dosáhne jeho vhodným umístěním do zařazovaného příkazu jazyka C). L) Argumenty "< položka" a "<< položka" Při uvedení argumentu "< položka" nebo "<< položka" se volané funkci předává délka této položky (smí být i proměnná), a to převedená do typu "short" (při <, smí však být nejvýše 32767 bytů) resp. do typu "long" (při <<) . Namísto položky lze uvést i speciální index, jehož délka je ovšem vždy 4 byty. Poznámka: Argument "< položka" resp. "<< položka" má smysl především při proměnné délce; při pevné délce pouze tehdy, když ji programátor nezná (např. délka 01 zařazované příkazem COPY nebo v případě, že se očekává změna délky této položky při pozdějších opravách programu apod.). Příklad: Chce-li uživatel předat funkci KAREL adresu a délku ("long") položky ALFA a adresu a hodnotu ("double") položky BETA, píše CALL 'KAREL' USING ALFA <