Makrá #

Prostredie CircuitMacros je rozšírením programovacieho jazyka dpic určeného pre kreslenie diagramov a grafov (staršia verzia je označovaná ako gpic) pomocou súboru makier pre makroprocesor m4. Makrá môžeme považovať za malé programy alebo skripty, ktorými sú nahradzované ich mená pri ich použití v hlavnom programe. Pomocou rozšírenia jazyka dpic makrami je možné vytvárať elektrické zapojenia a schémy, zároveň je možné v nich používať aj grafické prvky jazyka dpic.

Makroprocesor m4

Makroprocesor je univerzálny program pre spracovanie makier široko využívaný v programátorskej praxi najmä pri jazykoch nižšej úrovne a assembleroch. Makrá nachádzajú uplatnenie v rôznych implementáciách aj v textových a tabulkových procesoroch. Makroprocesor kopíruje vstupný text zo vstupu na výstup a popritom prí nájdení mena vopred definovaného makra

  • nahrádza meno makra textom z definície makra

  • nahrádza parametre makra ich hodnotami

  • vkladá súbory

  • prevádza manipulácie s textovými reťazcami

  • vyhodnocuje podmienky

  • vyhodnocuje aritmetické výrazy

Referenčnou implementáciou makroprocesora m4 je GNU M4.

Makrá definované v knižniciach CircuitMacros expandujú značky elektronických prvkov do množiny príkazov jazyka dpic, z vytvoreného programu je pomocou interpreteru príkazov vygenerovaný výsledný obrázok vo zvolenom rastrovom alebo vektorovom formáte.

_images/cm_0165a.png

Obr. 55 Postup generovania obrázkov.#

Warning

Kódy makier sú v podstate pomenované textové reťazce, ktorými nahrádza makrorocesor pred samotným spracovaním zdrojového kódu všetky časti zdrojového kódu zhodné s menom makra. Táto substitúcia je čisto mechanická, bez ohľadu na kontext v ktorom sa text zhodný s menom makra vyskytuje. Toto môže spôsobiť pri interpretácii kódu chybu, ktorá je spôsobená substitúciou makra na nevhodnom mieste a to aj napriek tomu, že kód programu je formálne syntakticky správny.

R1: resistor;
"terminal resistor" at R1.c above;   # chyba, substitucia v texte

Pre odstránenie tejto chyby je potrebné vhodným spôsobom pozmeniť text tak, aby makroprocesor text nenahrádzal, napríklad

"terminal res\\istor" at R1.c above; # dve lomítka \\ sú pri zobrazení ignorované 

Inou možnosťou je vložiť konfliktný text do úvodzoviek makra m4, ktoré makroprocesor ignoruje

"terminal `resistor' " at R1.c above; # `text' je ignorovaný

Použitie makier #

Makrá sa definujú podľa syntaxe makroprocesora m4. Všeobecný tvar makra je

define (name, [expansion])

Reťazec name je nahradený reťazcom expansion, typ úvodzoviek v makre je dôležitý. Príklad vytvorenia makra a jeho použitia

define(`foo', `Hello world.')
_images/pck_03.png

Obr. 56 Vytvorenie a použitie makra.#

Makro môže mať argumenty, tieto sú označované ako $1, $2 … , špeciálny význam má argument označený ako $0, ktorý obsahuje meno makra. Príklady použitia jednoduchých makier s argumentami

define(`exr', `$2, $1')               # zamena poradia argumentov 
exr(abc, 123)                         # -->  123, abc

define(`exc', `$1.y, $1.x')           # vymena zložiek súradnice
P: (3,1)
sprintf("(%2.0f, %2.0f)", exc(P))     # --> (1,3) 

Poznámka

Substitučné reťazce v makrách m4 začínajú znakom spätného apostrofu chr(96) a končia znakom apostrofu chr(39). Textové reťazce v jazyku dpic začínajú a končia úvodzovkami ".

_images/keyb.png

Vytvorenie makra #

Pri tvorbe makier pre kreslenie vlastných prvkov zapojenia môžeme využiť nasledujúci vzor, v ktorom sú v makre vyhodnotené dva parametre. Ako substitučný reťazec použijeme kód uzatvorený v bloku [...], čo nám umožní reprezentovať makro ako zložený objekt a v makre pre kreslenie používať absolútne súradnice.

#----------------------------------------------
# vzor(n, c) - template pre makro
# n - numericky parameter
# c - znakovy parameter L|R|U|P
#----------------------------------------------
define(`vzor',`[
    # kontrola existencie numerickeho parametra
    # pri chybajucom parametri nahradenie default hodnotou
    
    ifelse(defn(`par1'),  $1, par1=1,  par1=$1)    

    # vyber indexu 0...3 z preddefinovanej množiny parametrov L R U P 
    # pri neexistujucej ma index hodnotu -1
    
    par2 = index(`LRUD', $2)

    # vyhodnotenie pre hodnoty parametra podla hodnoty indexu
    if par2 <= 0 then  { line -> left_  par1; } 
    if par2 == 1 then  { line -> right_ par1; }
    if par2 == 2 then  { line -> up_    par1; } 
    if par2 == 3 then  { line -> down_  par1; } 
]')

Makro defn() v predlohe vytvorí premennú par1 a skontroluje existenciu argumentu $1, ak tento neexistuje, ifelse priradí par1=1, ak existuje, tak potom jej priradí hodnotu par1=$1. Premenná par2 je inicializovaná hodnotou indexu z poľa dovolených parametrov. Makro pri použití pokrýva nasledujúce prípady

vzor;        -> vzor(1,L)
vzor();      -> vzor(1,L)
vzor(2);     -> vzor(2,L)
vzor(3,R);   -> vzor(3,R)
vzor(,X);    -> vzor(1,L)
vzor(,);     -> vzor(1,L)     

Nižšie je uvedené makro pre zobrazenie spínača s parametrami dĺžka spínača a ‘stav (ON, OFF) spínača. Aby bol komponent presne umiestnený v mriežke bez ohľadu na jeho aktuálne grafické zobrazenie, je vhodné ho umiestniť do neviditeľného boxu s fixnými rozmermi. Pre vonkajší box potom platia štandardné atribúty w,e,s,n,nw ….

Implementácie makra #

Nasledujúci príklad implementuje zobrazenie spínača s dvoma parametrami - dĺžka spínača a stavu zopnutia (ON, OFF) spínača. Aby bol komponent presne umiestnený v mriežke bez ohľadu na jeho aktuálne grafické zobrazenie, je vhodné ho umiestniť do neviditeľného boxu s fixnými rozmermi. Pre vonkajší box potom platia štandardné atribúty w,e,s,n,nw ….

Pre ilustráciu je zobrazený vonkajší box, ktorý umožňuje ukladanie komponentu v rastri, parameter invis spôsobi skrytie obrysu.

# horizontal switch
# usage:
#     swh(length, ON | OFF );
define(`swh',`[

    B:  box ht 1 wid $1 dotted 0.04 #invis;   # vonkajsi okraj pola 1. parametra
        rr = 0.15;
        p = 1.5; 
    
    C1: circle diameter rr at  B.c + (rr/2 - p/4, 0)
    C2: circle diameter rr at  B.c + (-rr/2 + p/4, 0) fill 0;
        line from C1.w to B.w
        line from C2.e to B.e
        ifinstr($2,OFF,                        # kontrola hodnoty 2. parametra
            {   # stav OFF
                line from C2.c to C1.c + (0, p/4)
            },
            {   # stav ON
                line from C2.c to C1.c 
            }
        );
]')

Vytvorené makro požívame ako akýkoľvek iný príkaz pre kreslenie prvkov zapojenia. Príklad použitia implmentovaného spínača je v nasledujúcom kóde, pre názornosť je ponechané zobrazenie vonkajšieho obrysu prvku.

move to (0.5, 2); right_; 
swh(1, OFF);
line 0.5;
swh(1, ON);
line 0.5;
swh(2, OFF);
dot;
{ line up_   1; right_; S1: swh(2,  ON); "$S_1$" at S1.n; }
{ line down_ 1; right_; S2: swh(2, OFF); "$S_2$" at S2.n; }
_images/cm_0165c.png

Obr. 57 Implementácia makra pre zobrazenie spínača a jeho použitie#

Konflikt mien

Používanie makrier spoločne s interpreterom môže byť niekedy zdrojom chýb. Problémom môže byť hlavne to, že o chybe spôsobenej nesprávnym použitím makie sa dozvieme až pri interpretácii kódu s expandovanými makrami, pričom sa zvyčajne nedozvieme, z ktorého makra a na ktorom riadku zdrojového kódu k chybe došlo.

  • Niektoré makrá definujú premenné a konštanty, ktoré môžu byť príčinou konfliktov. Napríklad makro setrgb() používa premenné r_ , g_, b_, kde prvá premenná vytvorí konflikt s menom, ak potrebujeme napríklad označiť rezistor pomocou syntaxe v LaTex-u napr. r_1. V takomto prípade je potrebné v reťazci pre LaTeX použiť formálne prerušenie reťazca r\_1.

  • Nie je možné priamo v zobrazovanom texte použiť mená makrier, napríklad “toto je resistor R1”, pretože pri substitúcii dôjde k nahradeniu textu resistor kódom definovanom v makre a následnej chybe pri interpretácii zdrojového kódu. Text musíme upraviť podobne ako v predchádzajúcom prípade.

Modifikácia makra #

V niektorých prípadoch nepotrebujeme vytvárať nové makro, ale len rozšíriť existujúce makro o ďalši popis alebo grafiku. V niektoých zapojeniach napríklad je značka rezistora doplnená o označenie jeho výkonovej straty, ktorá môže súvisieť s jeho typom púzdra.

define(`res_025w', `[
    R: resistor($1,$2,$3);
    dx = 0.065*linewid;
    line from R.c+(dx,-dx) to R.c+(-dx,dx);
]')
_images/cm_0165d.png

Obr. 58 Príklad použitia modifikovaných makier.#