• Aucun résultat trouvé

9. Les macros

9.4. Macros vardef

Une définition de macro peut commencer avecvardef au lieu dedef. Les macros définies de cette manière sont appelées des macrosvardef. Elles sont particulière-ment bien adaptées pour des applications dans lesquelles les macros sont utilisées en guise de fonctions ou de sous-routines. L’idée principale est qu’une macrovardefest comme une variable du type « macro ».

Au lieu dedef<tokensymbolique>, une macrovardefcommence par vardef<variable générique>

où une<variable générique>est un nom de variable avec un indice numérique rem-placé par le symbole générique d’indice [ ]. En d’autres termes, le nom suivantvardef obéit exactement à la même syntaxe que celle des noms donnés dans une déclaration de variable. Il s’agit d’une séquence detagset de symboles d’indice générique com-mençant avec untag, où letagest untokensymbolique qui n’est ni une macro ni une primitive comme cela est expliqué dans la section 6.2.

Le cas le plus simple est celui d’un nom de macrovardefconstitué d’un simpletag.

Dans de telles circonstances,defetvardefprocurent approximativement les mêmes fonctionnalités. La différence la plus évidente est que begingroup et endgroup sont automatiquement insérés au début et à la fin du<texte de remplacement>dans chaque macrovardef. Ceci considère le<texte de remplacement>comme un groupe de telle sorte qu’une macro vardef se comporte comme un appel de sous-routine ou de fonction.

Une autre propriété des macros vardef est qu’elles permettent des noms de macro multi-tokenset des noms mettant en jeu des indices génériques. Lorsque le nom d’une macro vardef possède des indices génériques, il faut donner des valeurs numériques lorsque la macro est appelée.

Après une définition de macro

vardef a[]b(expr p) =<texte de remplacement>enddef ;

a2b((1,2))eta3b((1,2)..(3,4))sont des appels de macro.

Mais comment le<texte de remplacement>peut-il faire la différence entre a2bet a3b? Deux paramètres suffixes implicites sont fournis à ce propos. Chaque macro vardef possède les paramètres #@ et@, où @est le dernier token dans le nom lors du dernier appel et#@correspond à tout ce qui précède le derniertoken. Ainsi #@

correspond àa2quand le nom donné esta2beta3lorsque le nom esta3b.

Supposons, par exemple, que la macroa[]bdoive prendre son argument et le trans-later d’une quantité qui dépend du nom de la macro. La macro pourrait être définie comme ceci

vardef a[]b(expr p) = p shifted(#@,b) enddef ;

Ainsia2b((1,2))signifierait(1,2) shifted (a2,b)eta3b((1,2)..(3,4)) signifierait((1,2)..(3,4)) shifted (a3,b).

Si la macro avait étéa.b[],#@serait toujoursa.bet le paramètre@donnerait l’indice numérique. Ainsia@se référerait à un élément du tableaua[]. Il faut noter que@est un paramètre suffixe et non un paramètre expression, de telle sorte qu’une expression comme@+1serait illégale. Le seul moyen pour attribuer des valeurs numériques d’un indice dans un paramètre suffixe est de les extraire de la chaîne de caractères renvoyée par l’opérateurstr. Cet opérateur nécessite un suffixe et renvoie une représentation chaîne de caractère d’un suffixe. Doncstr @serait"3"dansa.b3et"3.14"dans a.b3.14 oua.b[3.14]. Puisque la syntaxe pour un <suffixe>dans la figure 16 nécessite que les indices négatifs soient entre crochets,str @renvoie"[-3]"dans l’appela.b[-3].

L’opérateurstrest généralement réservé à des utilisations de dernier recours. Il est préférable d’utiliser des paramètres suffixes uniquement comme des noms de variables ou de suffixes. Le meilleur exemple d’une macro vardef mettant en jeu des suffixes est la macrozqui définit la conventionz. La définition met en jeu letokenspécial@#qui se réfère au suffixe qui suit le nom de la macro

vardef z@#=(x@#,y@#) enddef ;

def getmid(suffix p) =

pair p.mid[], p.off[], p.dir[] ; for i=0 upto 36 :

p.dir[i] = dir(5*i) ;

p.mid[i] + p.off[i] = directionpoint p.dir[i] of p ; p.mid[i] - p.off[i] = directionpoint -p.dir[i] of p ; endfor

enddef ;

def joinup(suffix pt,d)(expr n) = begingroup

save res, g ; path res ; res = pt[0]{d[0]} ; for i=1 upto n :

g := if (pt[i]-pt[i-1]) dotprod d[i] < 0 : - fi 1 ; res := res{g*d[i-1]} ... {g*d[i]}pt[i] ;

endfor res endgroup enddef ; beginfig(45) path p, q ;

p = ((5,2) .. (3,4) ... (1,3) ... (-2,-3) ... (0,-5) ... (3,-4) ... (5,-3) ... cycle) scaled .3cm shifted (0,5cm) ;

getmid(p) ; draw p ;

draw joinup(p.mid, P.dir, 36) .. cycle ; q = joinup(p.off, p.dir, 36) ;

draw q .. (q rotated 180) .. cycle ; drawoptions(dashed evenly) ;

for i = 0 upto 3 :

draw p.mid[9i] - p.off[9i] .. p.mid[9i] + p.off[9i] ; draw -p.off[9i] .. p.off[9i] ;

endfor endfig ;

FIG. 45 – CodeMETAPOST et la figure correspondante (la figure a subi une rotation deπ/2en raison du format de la feuille)

Cela signifie que n’importe quel nom de variable dont le premiertoken(ou initiale) est équivalent au couple de variables dont les noms sont obtenus en remplaçantz parxety. Par exemple,z.a1appelle la macrozavec le paramètre suffixe@#égal àa1. En général,

vardef<variable générique>@#

est une alternative àvardef<variable générique>qui conduit l’interpréteur META-POSTà rechercher un suffixe suivant le nom donné dans l’appel de la macro et le rend disponible comme paramètre suffixe@#.

Pour résumer les caractéristiques spéciales des macros vardef, elles permettent une large classe de noms de macro aussi bien que des noms de macro suivis par un paramètre suffixe spécial. De plus, begingroup et endgroup sont ajoutés automatiquement au<texte de remplacement>d’une macro vardef. Ainsi l’utilisation devardef au lieu dedef pour définir la macro joinup dans la figure 45 aurait évité d’inclure explicitementbegingroupetendgroupdans la définition de la macro.

En fait, la plupart des définitions de macro données dans les exemples précédents pourrait également utiliservardefau lieu dedef. Il est habituellement sans impor-tance d’utiliser l’une ou l’autre forme, mais une bonne règle générale est d’utiliser vardefsi l’on souhaite utiliser une macro comme une fonction ou une procédure.

La comparaison suivante devrait aider dans la décision d’utiliservardef :

– les macros vardef sont automatiquement encadrées par begingroup et end-group;

– la taille du nom d’une macrovardefpeut être supérieure à untokenet peut contenir des indices ;

– une macrovardef peut accéder au suffixe qui suit le nom d’une macro lors de l’appel de la macro ;

– lorsqu’untokensymbolique est utilisé dans le nom d’une macrovardef, il demeure untaget peut être encore utilisé dans d’autres noms de variables. Ainsip5direst un nom de variable légal même sidirest un nom d’une macrovardef, mais une macro ordinaire, telle que..., ne peut être employée dans un nom de variable (ceci est heureux puisquez5...z6est supposé être une expression de type chemin et non pas un nom de variable élaboré).