Hlavní navigace

Makro procesor GNU m4 (2)

1. 10. 2001
Doba čtení: 4 minuty

Sdílet

V dnešním dílu si pod drobnohledem prohlédneme proces expanze maker.
Expanze maker

Proces expanze maker je v činnosti m4 zásadní událostí, proto si jej popíšeme podrobněji. Předpokládejme, že m4 ze své vstupní pásky přečetlo slovo, které má přiřazenu definici makra. Procesor ve svých útrobách tuto definici v podobě řetězce znaků vyhledá, „přilepí“ ji na začátek vstupní pásky a pokračuje ve čtení vstupu od počátku. To znamená, že výsledek po expanzi makra je pokaždé znovu podroben zpracování procesorem. Klidně se v něm mohou objevit volání dalších maker nebo dokonce sebe sama a podobně.

Řekněme, že máme definováno makro makro1 tak, aby expandovalo na text „nazdar“. Takhle se m4 zachová:

   Volám makro1!
=> Volám nazdar!

Kdybychom navíc měli definováno makro nazdar na hodnotu „ahoj světe“, konečná podoba výstupu by vypadala takto:

   Volám makro1!
=> Volám ahoj světe!

Co se ve druhém případě přesně stalo? Procesor dostal do vínku vstupní pásku s řetězcem „Volám makro1“. Začne tuto pásku zpracovávat a nalezne token „Vol“. K němu není přiřazena žádná definice makra, proto slovo pouze vypíše v nezměněné podobě na výstup a pokračuje ve své práci. Znak „á“ je speciální, proto rovnou putuje na výstup. Následuje načtení tokenu „m“. Po kontrole svého vnitřního slovníku m4 zjistí, že se nejedná o žádné makro – znak zapíše na výstupní pásku. Za ním následuje mezera jakožto speciální znak. Následně procesor konečně načte slovo „makro1“, které je identifikátorem makra. K makru makro1 má m4 uloženu definici „nazdar“. Řetězec určený k nahrazení názvu makra vloží na počátek vstupní pásky. (Vstup v této chvíli vypadá asi takhle: „nazdar!“.) Pokračuje ve zpracovávání modifikované vstupní pásky a narazí na slovo „nazdar“. To je také identifikátorem makra, proto se celý postup opakuje. Řetězec „nazdar“ je na vstupu nahrazen jeho expanzí, totiž dvouslovím „ahoj světe“. Procesor jej znovu čte, ale žádné další makro už nenajde, proto vše kopíruje na výstup. Ve chvíli, kdy narazí na konec vstupní pásky, skončí.

Jednou z možností, jak zabránit expandování makra, je vložit řetězec do uvozovek:

   `makro1'
=> makro1

Pamatujete? Uvozený řetězec m4 neprohledává na výskyt maker, ale jednoduše jej posílá rovnou na výstup – a to je přesně to, co v téhle chvíli chceme.

Druhým způsobem je tohle:

   ma`'kro1
=> makro1

Procesor načte token „ma“, který ale neznamená nic, zapíše jej tedy na výstup. Druhým tokenem bude prázdný řetězec a pak token „kro1“, jenž rovněž nemá přiřazen žádný význam. – Heuréka! Slůvko „makro1“ je na výstupu!

Lehce přijdete i na další možnosti. Ale ty jsou jen variací těch předchozích:

   `m'akro1
=> makro1
   ma`kro'1
=> makro1
   mak`ro1'
=> makro1

Makra s argumenty

Používat makra jenom tak, jak jsme si dosud řekli, by bylo trochu chabé – nahrazovat text jiným umí i sed nebo podobné nástroje. Makra v m4 mohou však být volána navíc i s parametry, což uživateli přináší další aplikační možnosti. Žádost o expanzi makra s parametry se zapisuje takto:

nazev_makra(parametr1, parametr2, ..., parametrN)

Makra mohou mít libovolný počet argumentů. Jednotlivé parametry se oddělují čárkou. Otevírací závorka („(“) musí následovat přímo za názvem makra, bez oddělujících mezer, jinak bude makro zavoláno bez argumentů.

Vyžaduje-li volané makro více parametrů, než mu je dodáno, dostanou chybějící argumenty hodnotu prázdného řetězce. Je-li naopak makro voláno s nadbytkem parametrů, bude m4 ty přebývající jednoduše ignorovat.

Text:

nazev_makra()

je žádost o expanzi makra s jedním zadaným argumentem, který má hodnotu prázdného řetězce. Abyste zavolali makro bez argumentů, musíte jeho název napsat bez závorek:

nazev_makra

Při shromažďování argumentů dochází k expanzi maker, takže výsledek jednoho makra může být argumentem pro jiný. Jinými slovy, narazí-li m4 na název makra následovaný levou závorkou, přejde do speciálního stavu čtení argumentů. Název makra, které se má expandovat, si zapamatuje a pokračuje ve čtení vstupní pásky až po odpovídající uzavírací závorku. Přitom každé další makro, na které narazí, expanduje rekurzivně stejným postupem. Teprve když má načten celý řetězec tvořící všechny parametry, rozdělí jej podle čárek („,“) na jednotlivé argumenty a zapamatované makro expanduje.

Tedy například, jestliže „param“ expanduje na řetězec „, b, c“, volání makra:

makro(a param, d, e)

je žádostí o expanzi makra „makro“ s pěti parametry „a ", "b“, „c“, „d“ a „e“. Všimněte si, že první argument obsahuje mezeru, ale ostatní ne. Je to proto, že m4 ignoruje všechny „bílé znaky“ na začátku každého argumentu, zatímco všechny „bílé znaky“ na konci do hodnoty parametru zahrne. Chcete-li přesto mezeru na začátek argumentu dostat, musíte to procesoru m4 sdělit jejím uzavřením do uvozovek.

Aby to nebylo tak jednoduché, je zde navíc ještě jedno pravidlo týkající se výskytu neuvozených závorek uvnitř argumentů. Procesor si hlídá počty levých a pravých závorek v prostoru pro parametry makra, a ty se musí shodovat. Načítání parametrů tedy neskončí na prvním výskytu pravé závorky, ale až v místě odpovídající pravé závorky.

Volání:

CS24_early

makro((()

s největší pravděpodobností skončí s chybou „konec souboru v seznamu argumentů“ (EOF in argument list), protože m4 ke třem levým závorkám nikdy nenalezne jejich pravé ekvivalenty. Správný zápis je:

makro(`((')

Tímto jsme probrali celou problematiku čtení vstupu procesorem. Příště začneme s výkladem a popisem vestavěných maker. U dalšího pokračování se těší

Byl pro vás článek přínosný?

Autor článku

Michal Burda vystudoval informatiku a aplikovanou matematiku a nyní pracuje na Ostravské univerzitě jako odborný asistent. Zajímá se o data mining, Javu a Linux.