• Aucun résultat trouvé

Macros macro

N/A
N/A
Protected

Academic year: 2022

Partager "Macros macro"

Copied!
18
0
0

Texte intégral

(1)

Macros

macro = une fonction qui prend des fragments de code comme arguments et renvoie un nouveau fragment de code.

Les macros sont ex ´ecut ´ees lors de la compilation.

G ´en ´eralement utilis ´ees pour cr ´eer de nouvelles structures de contr ˆole, ou pour forcer une copie inline et ´eviter le co ˆut d’un appel de fonction

#define MIN(x,y) (x<y)?x:y int exp_min (exp *a, exp *b)

{ return MIN (exp_size (a), exp_size (b)); }

(2)

Macros

macro = une fonction qui prend des fragments de code comme arguments et renvoie un nouveau fragment de code.

Les macros sont ex ´ecut ´ees lors de la compilation.

G ´en ´eralement utilis ´ees pour cr ´eer de nouvelles structures de contr ˆole, ou pour forcer une copie inline et ´eviter le co ˆut d’un appel de fonction

#define MIN(x,y) (x<y)?x:y int exp_min (exp *a, exp *b)

{ return MIN (exp_size (a), exp_size (b)); } int exp_min (exp *a, exp *b)

{ return (exp_size (a) < exp_size (b))

? exp_size (a) : exp_size (b); }

(3)

Macro probl `emes

L’expansion textuelle peut consid ´erablement accroˆıtre la taille des programmes

Il est pr ´ef ´erable que l’expansion des macros se termine

La substitution textuelle des param `etres cause un m ´elange de port ´ee dynamique et de passage d’arguments par nom

#define swap(x,y) { int t = y; y = x; x = t; }

(4)

Macro probl `emes

L’expansion textuelle peut consid ´erablement accroˆıtre la taille des programmes

Il est pr ´ef ´erable que l’expansion des macros se termine

La substitution textuelle des param `etres cause un m ´elange de port ´ee dynamique et de passage d’arguments par nom

#define swap(x,y) { int t = y; y = x; x = t; } void proc (int a, int b, int t, int t2)

{ swap(a,b); /* {int t = b; b = a; a = t; } */

swap(t,t2); /* {int t = t2; t2 = t; t = t; } */

...

(5)

Blame et abstraction

Dans

#define swap(x,y) { int t = y; y = x; x = t; } ...

swap(t,t2);

...

A qui la faute?` Pourquoi?

(6)

Macro probl `emes textuels

Certains types de macros manipulent le texte

La cat ´egorie syntactique peut alors ˆetre autre que pr ´evue Ceci, `a l’appel et dans les param `etres

#define haha(x) {x

#define abs(x) (x<0) ? -x : x

#define swap(x,y) { int t = y; y = x; x = t; } ...

abs(a+1)*2 => (a+1<0) ? -a+1 : a+1*2 ...

if (a < b) if (a < b)

swap(a,b); => { int t = b; b = a; a = t; };

else else

(7)

Emacs Lisp (Elisp) primer

λx → e ( lambda (x) e)

e

1

e

2

(e

1

e

2

)

if e then e

t

else e

f

( if e e

t

e

f

) (e

1

, e

2

)

et

e

1

: e

2

fst

x

et head

x

snd

x

et tail

x

( cons e

1

e

2

) ( car x)

( cdr x) let x

1

= e

1

x

2

= e

2

in e

( let ((x

1

e

1

)

(x

2

e

2

))

e)

(8)

Macros en Lisp

Contrairement `a C o `u les macros op `erent sur le texte, en Lisp elles op `erent sur l’arbre de syntaxe

( defmacro

myand

(x y) (

list 0

if x y

nil

))

Dit de transformer les appels de la forme

(

myand

E

1

E

2

) = ⇒ ( if E

1

E

2 nil

)

( if E

1

E

2 nil

)

est `a la fois un morceau de code et une liste Homoiconicit ´e: m ˆeme syntaxe pour le code et les donn ´ees

(9)

Analyse de code

Une macro en Elisp peut analyser ses arguments

( defmacro

myand

(x y)

( if ( and (

consp

x) (

eq

(

car

x)

0myand

))

(

list 0myand

(

cadr

x) (

list 0myand

(

caddr

x) y )) (

list 0

if x y

nil

)))

Dit de transformer les appels de la forme

(

myand

(

myand

E

1

E

2

) E

3

) = ⇒ (

myand

E

1

(

myand

E

2

E

3

))

(10)

Un exemple de macro

(

dotimes

(x e

1

) e

2

)

Ex ´ecute

e

2 pour chaque valeur de

x

de 0 `a

e

1:

( defmacro

dotimes

(xl b)

( let ((x (

car

xl)) (l (

cadr

xl))) (

list 0

letrec

(

list

(

list 0loop

(

list 0

lambda (

list

x)

(

list 0

if (

list 0

≤ x l)

(

list 0

progn b (

list 0funcall 0loop

(

list 0

+ x 1)))))))

(

list 0funcall 0loop

0))))

(11)

Backquotes

Lisp offre une syntaxe sp ´eciale pour construire du code.

( defmacro

dotimes

(xl b)

( let ((x (

car

xl)) (l (

cadr

xl)))

8

( letrec ((

loop

( lambda (,x)

( if (≤ ,x ,l)

( progn ,b (

funcall loop

(+ ,x 1)))))))

(

funcall loop

0))))

(12)

Passage par nom

La borne est r ´e- ´evalu ´ee `a chaque fois, comme dans de l’appel par nom Nous voulons de l’appel par valeur

( defmacro

dotimes

(xl b)

( let ((x (

car

xl)) (l (

cadr

xl)))

8

( let ((

end

,l))

( letrec ((

loop

( lambda (,x)

( if (≤ ,x

end

)

( progn ,b (

funcall loop

(+ ,x 1)))))))

(

funcall loop

0)))))

(13)

Capture de nom

capture de nom = quand une manipulation du code change l’inter-

pr ´etation d’un identificateur, qui fait alors r ´ef ´erence `a une autre variable

( let ((

start

"-- " ) (

end

" --" )) (

dotimes

(y 10)

(

message

"%s%d%s"

start

y

end

)))

( let ((

start

"-- " ) (

end

" --" )) ( let ((

end

10))

( letrec

((

loop

( lambda (y)

( when (≤ y

end

)

(

message

"%s%d%s"

start

y

end

)

(

funcall loop

(+ y 1))))))

(14)

Gensym

Utilise des identificateurs tout frais pour ´eviter la capture de noms

( defmacro

dotimes

(xl b)

( let ((x (

car

xl)) (l (

cadr

xl))

(

endsym

(

gensym

)) (

loopsym

(

gensym

)))

8

( let ((,

endsym

,l))

( letrec ((,

loopsym

( lambda (,x)

( if (≤ ,x ,

endsym

)

( progn ,b (

funcall

,

loopsym

(+ ,x 1)))))))

( , 0)))))

(15)

Fonctions d’ordre sup ´erieur

D ´eplacer le code pour contr ˆoler la port ´ee

(

dotimes

(hxi hli) hbi)

devient

( let ((

body

( lambda (hxi) hbi)) (

end

hli))

( letrec ((

loop

( lambda (i)

( when (≤ i

end

) (

funcall body

i)

(

funcall loop

(+ i 1))))))

(

funcall loop

0)))

(16)

Fonctions d’ordre sup ´erieur (suite)

( defmacro

dotimes

(xl b)

( let ((x (

car

xl)) (l (

cadr

xl)))

8

( let ((

body

( lambda (,x) ,b)) (

end

,l))

( letrec ((

loop

( lambda (i)

( when (≤ i

end

) (

funcall body

i)

(

funcall loop

(+ i 1))))))

(

funcall loop

0)))))

(17)

Fonctions d’ordre sup ´erieur (fin)

( defmacro

dotimes

(xl b)

( let ((x (

car

xl)) (l (

cadr

xl)))

8

(

dotimes-f

( lambda (,x) ,b) ,l))) ( defun

dotimes-f

(

body end

)

( letrec ((

loop

( lambda (i)

( when (≤ i

end

) (

funcall body

i)

(

funcall loop

(+ i 1))))))

(

funcall loop

0)))))

(18)

Haskell

La paresse de Haskell lui permet de faire une partie de ce que font les macros

if3 x e1 e2 e3

= case x of { 0 => e1; 1 => e2; 2 => e3 }

De plus, l’usage de monades pour les effets de bord offre une

opportunit ´e suppl ´ementaire

while ct ce = loop

where loop = do t <- ct

if t

then do { ce; loop }

else return ()

Références

Documents relatifs

(2) Dans le fichier index.php, pour chaque film de la base, cr´ eer un lien vers fiche.php en envoyant un param` etre par la m´ ethode Get ou Post.. (3) R´ ecup´ erer l’id dans

– Un synoptique doit permettre de visualiser l’´ etat de la porte (ouverte, ferm´ ee, en ouverture, en fermeture), la pr´ esence d’un v´ ehicule devant la porte ` a

- Toute droite non parallèle à l’axe des ordonnées admet une équation de la forme y = ax + b, et représente donc une

Représenter dans le repère les courbes des fonctions g et h.. Représenter dans le repère les courbes des fonctions g

b) Choisir deux de ces ions et d´ecrire un test de reconnaissance pour chacun d’eux, ainsi que les ´equations- bilan correspondantes... c) L’eau de Volvic est-elle acide,

1. Enoncer la r`egle de l’octet. D´eterminer pour chacun leur nombre d’´electrons, ´etablir leur structure ´electronique ` a l’aide de la formule ´electronique puis `a l’aide

La fonction affine h représentée par la droite verte est h(x) = -1,5x ( il s’agit en fait d’une fonction linéaire ici, car la droite passe par l’origine du repère ).. 4)

4) Montrer que f réalise une bijection de [−1; 1] sur un intervalle [a; b] que l’on