10.3. Příkazy UFO a UFD (USE FOR THE OBJECT PROGRAM) Formát: - - | alfanumerický-literál | | položka | | speciální-index | | jméno-komunikační-oblasti | | jméno-souboru | { UFO | UFD } < jméno-třídicího-souboru > ... | * { položka | speciální-index } | | ** { num.pol. | UI-pol. | sp.index } | | *** { num.pol. | UI-pol. | sp.index } | | < { položka | speciální-index } | | << { položka | speciální-index } | - - Funkce: Příkaz UFO resp. UFD vyjadřuje úsek v jazyku C (s možností cobolského zápisu u některých cobolských objektů), který bude zařazen do přeloženého programu na místo odpovídající poloze příkazu UFO resp. UFD. Každý argument příkazu UFO resp. UFD určuje část tohoto úseku. Pro správné pochopení funkce příkazu UFO musí uživatel alespoň rámcově vědět, jak probíhá překlad cobolského zdrojového programu: Cobolský zdrojový program se jménem např. josef.cb je překládán nejprve do programu v jazyku C se jménem josef.c, mimoto se při překladu vytváří druhý soubor josef.d, jenž obsahuje některé deklarace a definice a bude includován do úvodní části programu josef.c. Pak bude program josef.c (včetně includovaného souboru josef.d) přeložen překladačem jazyka C. Příkaz UFO zapisuje úsek v jazyku C do vytvářeného programu josef.c, a to do oblasti přeložených příkazů na místo odpovídající poloze příkazu UFO v PROCEDURE DIVISION; je proto nezbytné vytvářet pomocí příkazu UFO kompletní a syntakticky správné příkazy jazyka C. Příkaz UFD zapisuje úsek v jazyku C do vytvářeného souboru josef.d, a to na jeho dosavadní konec; je proto nezbytné vytvářet pomocí příkazu UFD kompletní a syntakticky správné definice a deklarace jazyka C, které mohou stát před první funkcí. Jinak mají příkazy UFO a UFD přesně stejnou funkci: při týchž argumentech vytvoří přesně týž úsek jazyka C. Každý z argumentů příkazu UFO resp. UFD znamená určitý úsek jazyka C, který je nezávislý na předcházejících a následujících argumentech téhož příkazu UFO/UFD. Je proto zcela ekvivalentní uvést všechny potřebné argumenty v témže příkazu UFO/UFD anebo je jakkoliv rozdělit do několika příkazů UFO/UFD (třeba i pro každý argument uvést zvláštní příkaz UFO/UFD). A) Alfanumerický literál Alfanumerický literál smí mít libovolnou délku i obsah, pouze nesmí obsahovat byte s nulovou binární hodnotou (např. #434F424F4C004D58#). Tento literál bude bez jakékoliv změny a v plné délce zařazen do cílového C-programu. Příklad: UFD 'extern int pavel; extern char* petr;' #0A#. UFO '*(petr+pavel-1)=''A'';' #0A#. Předpokládejme pro určitost, že překládáme zdrojový program josef.cb. Příkaz UFD zapíše do souboru josef.d dvě deklarace externích proměnných (vyjádřené jediným alfanumerickým literálem), příkaz UFO zapíše do cílového C-programu josef.c jeden příkaz (vnitřní apostrofy jsou zde zdvojeny, při ekvivalentním zápisu "*(petr+pavel-1)='A';" by se nezdvojovaly). V obou příkazech UFD i UFO je uveden ještě druhý argument #0A#, jenž zapíše do souboru josef.d resp. josef.c jeden znak s hexadecimální hodnotou 0A vyjadřující přechod na nový řádek v souboru josef.d resp. josef.c (v jazyku C '\n'; vedle tabelátoru #09# je to jediný netisknutelný znak, který má smysl pomocí UFO/UFD zapisovat). Poznámka: Nezáleží na tom, jakým způsobem bude zařazovaný úsek rozdělen do jednotlivých alfanumerických literálů nebo i do několika za sebou následujících příkazů UFO/UFD. Týž úsek jako u výše uvedeného příkazu UFO se zařadí také např. pomocí příkazů UFO '*(' 'petr+pavel-' '1' UFO ')=' UFO "'A'" ';' UFO #0A#. Příklad: Příkaz jazyka C "exit(0);" zařadíme pomocí příkazu UFO 'exit(0);' #0A#. B) Položka Položka uvedená jako argument může být jakéhokoliv typu i délky a může mít kvalifikaci i indexy. Do cílového programu bude zařazen výraz jazyka C typu "unsigned char*" ("ukazatel na znak") vyjadřující adresu prvního bytu položky. Poznámka: V COBOLu DOS-3 bylo možno v příkazu UFO zapisovat též argumenty "položka ń k", kde k mohlo být celé číslo nebo celočíselná numerická položka. V našem COBOLu se tato možnost nepovoluje, neboť zvětšení resp. zmenšení adresy lze snadno vyjádřit následujícím alfanumerickým literálem nebo argumentem ve tvaru "* položka" (viz příklady). Z téhož důvodu nejsou v našem COBOLu implementovány argumenty typu "(externí-jméno)", "/ položka" a "= alfanumerický-literál". Argument typu "* ń k" nelze při překladu do jazyka C realizovat, argument "procedura" nebyl implementován kvůli implementačním obtížím. Příklad: 6.byte položky ALFA přeneseme na 13.byte položky BETA příkazem UFO '*(' BETA '+12)=*(' ALFA '+5);' Je-li začátek položky BETA vyjádřen výrazem např. W+58 a začátek položky ALFA výrazem např. L[4]+42, zařadí se do cílového C-programu příkaz "UFO *(W+58+12)=*(L[4]+42+5);". Příklad: 6.-37.byte položky A(I J) přeneseme na 13.-44.byte položky B(J K) příkazem UFO '{*(struct SSS {char x[32];}*)(' B(J K) '+12)=*(struct SSS*)(' A(I J) '+5);}' Tento příkaz UFO má tedy stejnou funkci jako příkaz STRING A(I J) POINTER 6 32 INTO B(J K) POINTER 13 32. Poznámka: Uveďme v příkazu UFO položku z LINKAGE SECTION nebo z FILE SECTION 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. Např. osmá položka úrovně 01 nebo 77 z LINKAGE SECTION, nepočítáme-li položky s REDEFINES, má přidělen ukazatel L[7]. Do cílového souboru se zařadí výraz jazyka C typu "unsigned char*" vyjadřující adresu úseku paměti přidělenou této položce, v našem případě právě toto L[7]. Je možné pomocí příkazu UFO zařadit takový příkaz jazyka C, jímž bude tento ukazatel L[7] naplňován adresou vhodného úseku paměti, čímž uvedenou položku s tímto úsekem paměti ztotožníme. Příklad: Potřebujeme mnohonásobně používat položku ALFA(I J K) a její podřízené položky. Abychom se vyhnuli mnohonásobnému vypočítávání adresy těchto položek při indexování, popíšeme v LINKAGE SECTION položku BETA s číslem úrovně 01 a popíšeme u ní stejné (až na jména) podřízené položky, jaké má položka A. Příkazem UFO BETA '=' ALFA(I J K) ';' #0A# zařadíme C-příkaz např. "L[7]=W+nnn;" (kde "nnn" nám zde zastupuje proměnný výraz s hodnotou rovnou rozdílu adresy položky ALFA(I J K) od začátku WORKING-STORAGE SECTION). Do ukazatele L[7] přiděleného položce BETA se dosadila adresa položky ALFA(I J K), čímž se s ní položka BETA ztotožnila. Při následujícím výpočtu pak kterýkoliv příkaz pracující s položkou BETA (nebo s položkami k ní podřízenými nebo spojenými s ní pomocí klauzule REDEFINES) bude ve skutečnosti pracovat s položkou ALFA(I J K) resp. s jejími podřízenými položkami. Příklad: V LINKAGE SECTION máme popsány položky SMRT a HROB s čísly úrovně 01 nebo 77. Předpokládejme, že položka SMRT již má přidělenu adresu úseku paměti. Příkaz UFO HROB '=' SMRT ';' #0A# zařadí C-příkaz např. "L[7]=L[12];", jenž přesune do ukazatele přiděleného položce HROB obsah ukazatele přiděleného položce SMRT, čímž ztotožní položku HROB s týmž úsekem paměti, s nímž je již ztotožněna položka SMRT. Naproti tomu příkazy UFD 'extern char* petr;' #0A# UFO HROB '=' petr ';' #0A# deklarují externí ukazatel petr a zařadí C-příkaz např. "L[7]=petr;", čímž ztotožní položku HROB s tím externím polem znaků, jehož adresa je vyjádřena ukazatelem petr. Příklad: Ve WORKING-STORAGE SECTION máme popsáno pole REMUS s maximálním možným počtem opakování (např. OCCURS 1000), přičemž skutečný počet opakování N zjistíme až během výpočtu. Rádi bychom zbytek pole REMUS využili pro nějaké jiné účely. Provedeme to tak, že v LINKAGE SECTION popíšeme položku ROMULUS s číslem úrovně 01 a ztotožníme ji s úsekem paměti začínajícím za koncem poslední položky REMUS(N) příkazem UFO ROMULUS '=' REMUS(N+1) ';' #0A# Poznámka: Výše uvedené příkazy UFO ztotožňující položku z LINKAGE SECTION s číslem úrovně 01/77 s vhodným úsekem paměti lze nahradit též příkazem CALL 'ICIDENT' takto: CALL 'ICIDENT' USING BETA ALFA(I J K) CALL 'ICIDENT' USING HROB SMRT CALL 'ICIDENT' USING HROB (petr) CALL 'ICIDENT' USING ROMULUS REMUS(N+1) Poznámka: Jméno komunikační oblasti (popsané klauzulí CD v COMMUNICATION SECTION) se v příkazu UFO/UFD považuje za speciální případ položky. Do cílového programu se zařadí výraz typu "unsigned char*" vyjadřující adresu prvního bytu komunikační oblasti. C) Speciální index Do cílového souboru bude zařazen výraz jazyka C typu "long" přidělený tomuto speciálnímu indexu pro uchování jeho hodnoty. (Např. při osmém speciálním indexu v rámci zdrojového programu to bude výraz "S[7]".) D) 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ů. Do cílového souboru bude tedy zařazen výraz jazyka C typu "struct sdtf" vyjadřující tuto strukturu přidělenou našemu souboru resp. třídicímu souboru. (Např. při souboru popsaném osmou klauzulí FD/SD ve FILE SECTION to bude výraz "F[7]".) Poznámka: Programátor by neměl ve struktuře přidělené souboru resp. třídicímu souboru nic měnit (leda po konzultaci s autory překladače). Učiní-li tak, zodpovídá pak sám za případný další chybný výpočet. Poznámka: Hodlá-li programátor zařadit do cílového programu volání funkce, jíž je třeba jako argument předat číslo, znakovou konstantu, řetězec nebo jméno externí proměnné resp. funkce, lze to v příkazu UFO snadno zařídit uvedením alfanumerického literálu. Je-li třeba jako argument předat adresu položky (tzn. úseku paměti přiděleného položce), stačí v příkazu UFO uvést tuto položku. Je-li třeba jako argument předat adresu ukazatele přiděleného položce z LINKAGE SECTION s číslem úrovně 01/77 nebo adresu "longu" přiděleného speciálnímu indexu nebo adresu struktury "struct sdtf" odpovídající souboru resp. třídicímu souboru, musí před tento argument zařadit ampersand & (pomocí alfanumerického literálu). Příklad: Do cílového programu zařadíme volání funkce vaclav, jíž jako argumenty předáme číslo -12, adresu položky A(I J), znakovou konstantu 'T', hodnotu prvního bytu položky B OF C, řetězec "PRAHA", hodnotu "shortu" začínajícího na adrese D(I) (např. když D(I) je dvoubytová binární položka), prvních 24 bytů položky E(I), adresu externí proměnné karel, hodnotu externí proměnné michal, hodnotu "doublu" začínajícího na 6.bytu pole, na něž ukazuje externí ukazatel martin (zde předpokládáme, že deklarace externích proměnných karel, michal a martin zařadí sám programátor pomocí příkazů UFD), adresu ukazatele přiděleného položce HROB s číslem úrovně 01 nebo 77 z LINKAGE SECTION, adresu úseku paměti ztotožněného s touto položkou HROB, adresu "longu" přiděleného speciálnímu indexu SI, hodnotu speciálního indexu SJ a adresu struktury "struct stdf" odpovídající souboru SOUB; hodnotu volání (typu "long") uložíme do čtyřbytové binární položky EMIL. Zařídíme to tímto příkazem UFO: UFO '*(long*)(' EMIL ')=vaclav(-12,' A(I J) ',''T'',' #0A09# '*(' B OF C '),"PRAHA",*(short*)(' D(I) '),' #0A09# '*(struct {char x[24];}*)(' E(I) '),' #0A09# '&karel,michal,*(double*)((char*)martin+5),' #0A09# '&' HROB ',' HROB ',&' SI ',' SJ ',&' SOUB ');' #0A#. Tento příkaz UFO zařadí do cílového programu např. takový příkaz jazyka C (kde "mmm", "nnn" atd. označují výrazy odpovídající indexování): *(long*)(W+58)=vaclav(-12,W+mmm,'T', *(W+84),"PRAHA",*(short*)(W+nnn), *(struct {char x[24];}*)(W+ppp), &karel,michal,*(double*)((char*)martin+5), &L[7],L[7],&S[5],S[6],&F[3]); E) Argumenty "* položka", "** položka" a "*** položka" Při uvedení argumentu "položka" se zařazuje adresa této položky. Naproti tomu při uvedení argumentu "* položka" nebo "** položka" nebo "*** položka" (srv. též příkaz CALL) se zařazuje hodnota této položky. Namísto položky lze uvést též speciální index. Platí zde tato pravidla: 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. Zařadí se takovýto výraz jazyka C: a) V případě jednobytové skupinové nebo alfanumerické položky se zařadí hodnota tohoto jediného bytu; např. *(W+58). b) V případě skupinové, alfanumerické nebo alfanumerické editované položky o pevné délce n > 1 se zařadí struktura zahrnující celou tuto položku; např. *(struct {char x[n];}*)(W+58). c) V případě rozpakované, pakované, binární nebo numerické editované položky s 0 dekadickými ciframi za desetinnou tečkou a s 1-4 dekadickými ciframi celkem se zařadí hodnota této položky převedená do typu "short"; např. *(short*)(W+58) u dvoubytové binární položky nebo icbditos(W+58,3) u rozpakované položky apod. d) V případě rozpakované, pakované, binární nebo numerické editované položky s 0 dekadickými ciframi za desetinnou tečkou a s 5-9 dekadickými ciframi celkem a dále v případě položky s USAGE INDEX a v případě speciálního indexu se zařadí hodnota této položky převedená do typu "long"; např. *(long*)(W+58) u čtyřbytové binární položky nebo u UI-položky, icbpatol(W+58,5) u pakované položky nebo S[3] u speciálního indexu apod. e) V případě exponenciální krátké položky se zařadí hodnota této položky převedená do typu "float"; např. *(float*)(W+58). f) V případě jakékoliv jiné numerické položky (tzn. položky s nenulovým počtem cifer za desetinnou tečkou nebo položky s více než 9 dekadickými ciframi celkem nebo exponenciální dlouhé nebo znakové položky) se zařadí hodnota této položky převedená do typu "double"; např. icbditod(W+58,10) u rozpakované položky nebo *(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. Zařazený výraz jazyka C bude stejný jako při jedné hvězdičce s tím rozdílem, že nikdy nevzniká výraz typu "short" a že u všech celočíselných numerických položek vzniká výraz typu "long": a) V případě rozpakované, pakované nebo numerické editované položky s 0 dekadickými ciframi za desetinnou tečkou, v případě binární položky s 0 dekadickými ciframi za desetinnou tečkou a s 1-9 dekadickými ciframi celkem a dále v případě položky s USAGE INDEX nebo speciálního indexu se zařadí hodnota této položky převedená do typu "long"; např. (long)*(short*)(W+58) u dvoubytové binární položky nebo icbditol(W+58,10) u rozpakované položky atd. b) V případě exponenciální krátké položky se zařadí hodnota převedená do typu "float". c) V případě jakékoliv jiné numerické položky se zařadí hodnota převedená do typu "double". 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. Zařazený výraz jazyka C bude představovat hodnotu položky vždy převedenou do typu "double"; např. (double)*(long*)(W+58) pro čtyřbytovou binární položku, icbditod(W+58,3) pro rozpakovanou položku atd. Poznámka: Výše uvedená pravidla lze vyjádřit též takto: a) U položek s nenulovým počtem cifer za desetinnou tečkou, u osmibytových binárních položek a u exponenciálních dlouhých a znakových položek se při libovolném počtu hvězdiček vždy zařazuje hodnota převedená do typu "double". (Pokud tedy uživatel např. při PIC 99V99 a hodnotě 12.34 chce zařadit hodnotu 1234 ve tvaru "short", musí si položku redefinovat pomocí položky s PIC 9999 a tuto pak uvést v příkazu UFO. Jinak nezávisle na počtu hvězdiček bude zařazena hodnota 12.34 převedená do typu "double". b) U rozpakovaných, pakovaných, numerických editovaných a nejvýše čtyřbytových binárních položek s nulovým počtem cifer za desetinnou tečkou se zařazuje hodnota převedená do typu: - Při 1-4 dekadických cifrách: při * "short", při ** "long", při *** "double". - Při 5-9 dekadických cifrách: při * nebo ** "long", při *** "double". - Při 10-30 dekadických cifrách (netýká se binárních položek!): při * "double", při ** "long" (!!!), při *** "double". Výjimku zde zřejmě tvoří rozpakované, pakované a numerické editované položky s 0 ciframi za a 10-30 ciframi před desetinnou tečkou, které jsou při ** převáděny do typu "long". Uživatel musí zajistit, aby hodnota takovéto položky byla alespoň -2147483648 a nejvýše +2147483647 (srv. též definici celočíselné položky v 4.5.3.C1). c) U exponenciálních krátkých položek se zařazuje hodnota převedená při * nebo ** do typu "float", zatímco při *** do typu "double". Poznámka: Zařazuje-li uživatel pomocí příkazu UFO nějaké výpočty, stačí většinou jediná hvězdička; výjimku tvoří pouze celočíselné položky s více než 9 ciframi, jejichž hodnota má být převedena do typu "long" - to uživatel zařídí pomocí dvou hvězdiček. Jinak mají dvě nebo tři hvězdičky význam pouze při zařazování volání funkce, u jejíchž parametrů je předepsán typ "long" nebo "double" - to pak uživatel zařídí pomocí dvou nebo tří hvězdiček. Příklad: M-tý byte položky A máme nahradit N-tým bytem položky B. Provedeme to příkazem UFO '*(' A '+' *M '-1)=*(' B '+' *N '-1);' #0A# jímž zařadíme např. takový příkaz jazyka C: *(W+24+*(long*)(W+12)-1)=*(W+36+icbditos(W+3,5)-1); Kterákoliv z položek A, M, B, N mohla mít uvedeny indexy. Pokud by však některá z položek M nebo N měla více než 9 dekadických cifer, bylo by nutno psát **M resp. **N. Příklad: Chceme zařadit volání funkce 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". (Kde obě tyto položky mají např. PIC 999.) Můžeme pak psát UFO 'jaroslav(' **ALFA ',' ***BETA ');' #0A# což je přehlednější a vede na efektivnější výpočet než UFO 'jaroslav((long)(' *ALFA '),(double)(' *BETA '));' #0A#. F) Argumenty "< položka" a "<< položka" Při uvedení argumentu "< položka" nebo "<< položka" se zařazuje délka této položky (smí být i proměnná). Při "< položka" bude mít tato délka typ "short" nebo "long", při "<< položka" bude mít tato délka vždy typ "long" (což má význam pouze v případě, že tato délka je zařazována jako parametr funkce, která na tomto místě očekává typ "long"). Namísto položky lze uvést též speciální index, jeho délka je ovšem vždy 4 byty. Poznámka: Zařazování délky položky 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: Uživatel chce zařadit deklaraci statického pole o délce rovné (pevné leč neznámé) délce položky PODNIK: UFD 'static unsigned char POLE['