Hlavní navigace

Makro procesor GNU m4 (4)

Michal Burda 16. 10. 2001

V dnešním dílu nás čeká nepřímé volání maker a podmínkové příkazy.

Přejmenování maker

V m4 je možno získat uvozený řetězec definice makra. Slouží k tomu vestavěné makro

defn(`nazev_makra')

Uvedenou vlastnost můžete použít pro ladicí účely, ke kopírování nebo
přejmenování makra.
Je-li makro definované uživatelem, je výsledkem expanze jeho definice uzavřená
do uvozovek. Jestliže se však defn použije na vestavěné makro procesoru
m4, makro expanduje na speciální token odkazující na vnitřní definici makra.
Tento token je smysluplný jenom jako druhý parametr k define nebo
pushdef; v jakémkoliv jiném kontextu (třeba při pokusu o jeho vypsání
na výstup) je ignorován.

Následující ukázka zobrazí definici makra makro:

   define(`makro', `Makro `$0' získalo $# argumentů')
=>
   defn(`makro')
=> Makro `$0' získalo $# argumentů

Jen tak cvičně, přejmenujme si makro undefine na vymaz:

   define(`vymaz', defn(`undefine'))
=>
   vymaz(`undefine')
=>
   undefine(`vymaz')
=> undefine(`vymaz')

Makro defn je rozpoznáváno pouze s parametry.

Nepřímé volání maker

V odstavci o definici maker jsem vám slíbil, že prozradím, jak volat makro s nepřípustným názvem. Už vám tedy nebudu déle tajit, že existuje vestavěné makro

indir(`nazev_makra' [, parametry, ...])

Volání indir donutí m4 expandovat makro s názvem v prvním parametru a
předat mu zbytek argumentů. Klidně můžete dělat tohle:

   indir(`define', `makro', `ahoj')
=>
   makro
=> ahoj

ale mnohem užitečnější je něco takového:

   define(`$vnitrni_makro', `Jen pro nepřímé volání!')
=>
   $vnitrni_makro
=> $vnitrni_makro
   indir(`$vnitrni_makro')
=> Jen pro nepřímé volání!

Jak vidíte, mechanismus můžete použít k definování „soukromých“ maker, která slouží jen pro vnitřní účely a u kterých takto nehrozí, že budou uživatelem volány omylem.

Z podobného soudku je i makro

builtin(`nazev_makra' [, parametry, ...])

sloužící k nepřímému volání vestavěných maker. Všechna standardní makra procesoru m4 si můžete předefinovat podle svých představ, přitom ale neztratíte možnost volat kterékoliv z nich právě pomocí makra builtin:

   define(`makro', `nazdar')
=>
   define(`undefine', `ahoj')
=>
   undefine(`makro')
=> ahoj
   makro
=> nazdar
   builtin(`undefine', `makro')
=>
   makro
=> makro

Ovšem, předefinujete-li si i makro builtin, nepomůže vám už ani svěcená voda :-).

Makro builtin je expandováno jen s parametry. Není tomu tak u indir, které bez argumentů zahlásí chybu:

   indir
E> stdin:1: m4: Undefined macro `'

Testování definice makra

Expanze maker na holý text, ačkoliv ji můžeme ovlivnit parametry, je užitečná jen v omezených případech. Obvykle potřebujeme něco víc: aby makro expandovalo na různé výstupy v závislosti na rozhodnutích uskutečněných za chodu, tj. potřebujeme nějaký druh podmínkových příkazů. GNU m4 poskytuje dva základní příkazy větvení. Prvním z nich je ifdef:

ifdef(`nazev_makra', výsledek1 [, výsledek2])

Příkaz umožňuje testovat, zda je nějaké makro definováno, nebo ne. Jestliže má identifikátor nazev_makra přiřazenou definiční hodnotu, ifdef expanduje na „výsledek1“. V opačném případě bude výstupem řetězec „výsledek2“. Třetí argument makra ifdef je volitelný, proto když jej neuvedete, použije se ve shodě s pravidly procesoru prázdný řetězec.

   define(`vypis_autora', `ifdef(`$autor',
                                 `Autor: indir(`$autor')',
                                 `neznámý autor')')
=>
   vypis_autora
=> neznámý autor
   define(`$autor', `Karel Zelený')
=>
   vypis_autora
=> Autor: Karel Zelený

Makro ifdef je rozpoznáváno jen s argumenty.

Porovnávání řetězců

Poněkud užitečnějším podmínkovým příkazem je vestavěné makro ifelse:

ifelse(poznámka)
ifelse(řetězec1, řetězec2, rovnají se [, nerovnají se])
ifelse(řetězec1, řetězec2, jsou rovny, ...)

Použijete-li jej jenom s jedním argumentem, nestane se nic a výsledkem bude prázdný řetězec. Z tohoto důvodu je makro ifelse občas využíváno pro různé poznámky.

   ifelse(`Tak tohle je nějaká poznámka.')
=>

Stejného účinku, ale čitelnějšího zdrojového kódu dosáhnete třeba
takto:

   define(`poznamka', `')
=>
   poznamka(`
   Tohle je dlouhatánská poznámka,
   která se na výstupu neobjeví.
   ')
=>

Má-li ifelse tři nebo čtyři parametry, provádí porovnávání prvních dvou argumentů. Jsou-li si řetězec1 a řetězec2 rovny, expanduje ifelse na řetězec „rovnají se“. V opačném případě bude výsledkem volitelný čtvrtý argument „nerovnají se“ (nebo prázdný řetězec, pokud čtvrtý parametr neuvedete).

   ifelse(`pepa', `teta', `stejné')
=>
   ifelse(`pepa', `pepa', `stejné')
=> stejné
   ifelse(`pepa', `teta', `stejné', `různé')
=> různé
   ifelse(`teta', `teta', `stejné', `různé')
=> stejné

Makro ifelse ale umí zpracovat i více argumentů než jenom čtyři. Jsou-li první dva argumenty shodné, expanduje ifelse na text třetího parametru. Jinak se vše opakuje bez prvních tří argumentů – tedy porovnává se čtvrtý a pátý parametr a v případě shody se vrátí šestý argument atd. Chybí-li makru argumenty pro další porovnávání a všechna předchozí porovnání dopadla neúspěšně, použije se pro expanzi případný poslední argument. Viz příklad:

   ifelse(`pepa', `teta', `1 = 2',
          `teta', `běta', `4 = 5',
          `nerovnají se')
=> nerovnají se
   ifelse(`pepa', `teta', `1 = 2',
          `teta', `běta', `4 = 5')
=>
   ifelse(`pepa', `teta', `1 = 2',
          `teta', `teta', `4 = 5',
          `nerovnají se')
=> 4 = 5
   ifelse(`teta', `teta', `1 = 2',
          `teta', `teta', `4 = 5',
          `nerovnají se')
=> 1 = 2

Pochopitelně, v praxi bude ifelse používáno situacích mnohem složitějších, než byly zde uvedené. Jeho zásadní použití tkví v rekurzivně volaných makrech, ale o tom někdy příště.

Makro ifelse je rozpoznáváno jen s argumenty.

Našli jste v článku chybu?

7. 9. 2009 13:07

Pety (neregistrovaný)

Jen navrh na upravu :

< define(`makro', `Makro `@@@' získalo $# argumentů')
> define(`makro', `Makro `$0' získalo $# argumentů')

< => Makro `@@@' získalo $# argumentů
> => Makro `$0' získalo $# argumentů

Pety aka Poke.






Root.cz: Pinebook: linuxový notebook za 89 dolarů

Pinebook: linuxový notebook za 89 dolarů

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Podnikatel.cz: Babiše přesvědčila 89letá podnikatelka?!

Babiše přesvědčila 89letá podnikatelka?!

Lupa.cz: Propustili je z Avastu, už po nich sahá ESET

Propustili je z Avastu, už po nich sahá ESET

Lupa.cz: Co se dá měřit přes Internet věcí

Co se dá měřit přes Internet věcí

120na80.cz: Horní cesty dýchací. Zkuste fytofarmaka

Horní cesty dýchací. Zkuste fytofarmaka

Měšec.cz: Jak levně odeslat balík přímo z domu?

Jak levně odeslat balík přímo z domu?

Vitalia.cz: Znáte „černý detox“? Ani to nezkoušejte

Znáte „černý detox“? Ani to nezkoušejte

Měšec.cz: Kdy vám stát dá na stěhování 50 000 Kč?

Kdy vám stát dá na stěhování 50 000 Kč?

DigiZone.cz: Recenze Westworld: zavraždit a...

Recenze Westworld: zavraždit a...

Vitalia.cz: Spor o mortadelu: podle Lidlu falšovaná nebyla

Spor o mortadelu: podle Lidlu falšovaná nebyla

DigiZone.cz: Flix TV má set-top box s HEVC

Flix TV má set-top box s HEVC

Lupa.cz: Proč firmy málo chrání data? Chovají se logicky

Proč firmy málo chrání data? Chovají se logicky

120na80.cz: Pánové, pečujte o svoje přirození a prostatu

Pánové, pečujte o svoje přirození a prostatu

Měšec.cz: Air Bank zruší TOP3 garanci a zdražuje kurzy

Air Bank zruší TOP3 garanci a zdražuje kurzy

Měšec.cz: U levneELEKTRO.cz už reklamaci nevyřídíte

U levneELEKTRO.cz už reklamaci nevyřídíte

120na80.cz: Jak oddálit Alzheimera?

Jak oddálit Alzheimera?

DigiZone.cz: Sony KD-55XD8005 s Android 6.0

Sony KD-55XD8005 s Android 6.0

Podnikatel.cz: EET: Totálně nezvládli metodologii projektu

EET: Totálně nezvládli metodologii projektu

DigiZone.cz: Rádio Šlágr má licenci pro digi vysílání

Rádio Šlágr má licenci pro digi vysílání