• Aucun résultat trouvé

Travail pratique #2 IFT-2030 November 7, 2005

N/A
N/A
Protected

Academic year: 2022

Partager "Travail pratique #2 IFT-2030 November 7, 2005"

Copied!
9
0
0

Texte intégral

(1)

Travail pratique #2

IFT-2030 November 7, 2005

¡¡ Dˆ u le 21 novembre ` a midi puis le 30 novembre ` a 8h30 !!

1 Survol

Ce TP a pour but de vous familiariser avec le langage C, les pointeurs, la gestion de m´emoire explicite.

Comme pour le TP pr´ec´edent, les ´etapes sont les suivantes:

1. Parfaire sa connaissance de C.

2. Lire et comprendre cette donn´ee.

3. Lire, trouver, et comprendre les parties importantes du code fourni.

4. Compl´eter le code fourni.

5. ´Ecrire un rapport. Il doit d´ecrire votre exp´erience pendant les 4 points pr´ec´edents: probl`emes rencontr´es, surprises, choix que vous avez dˆu faire, options que vous avez sciemment rejet´ees, etc... Le rapport ne doit pas exc´eder 5 pages.

Comme pour le TP1, les 3 premiers points occuperont probablement une large part du temps total.

Ce travail est `a faire en groupes de 2 ´etudiants. Le rapport (au format PDF ou Postscript) et le code sont `a remettre par remise ´electronique avant la date indiqu´ee. Aucun retard ne sera accept´e. Indiquez clairement votre nom au d´ebut de chaque fichier.

Si un ´etudiant pr´ef`ere travailler seul, libre `a lui, mais l’´evaluation de son travail n’en tiendra pas compte. Si un ´etudiant ne trouve pas de partenaire, il doit me contacter au plus tard lundi 14 d´ecembreavantle cours. Des groupes de 3 ou plus sontexclus.

La remise est `a faire en 2 temps. Le 21 novembre, vous devez remettre la solution de la premi`ere partie du travail (i.e. exp free), et le 30 novembre vous devez remettre la version finale et le rapport.

(2)

2 Une sorte de ML

Vous allez compl´eter une partie d’un compilateur d’un langage inspir´e de ML et Haskell. Ce langageµMLcomprend des expressions de la forme suivante:

e ::=n Un entier sign´e en d´ecimal

|”. . .” Une chaˆıne de caract`eres

|x Une variable

|(e) Parenth`eses

|(e:τ) Annotation de type

|(e1, e2) Une paire

|#1e|#2e Acc`es aux champs d’une paire

|e1+e2|e1−e2 |e1∗e2 |e1/ e2 Arithm´etique infixe

|fnargs⇒e Fonction anoynyme

|e1e2 Appel de fonction

|ife1 thene2 elsee3 Expression conditionelle

|letdeclsine D´efinitions locales de variables et fonctions decls ::=decl{ ; decl}

decl ::=x[ : τ ] =e D´efinition de variable

|f args[ : τ ] =e D´efinition de fonction args ::= (x11). . .(xnn) Liste d’arguments

τ ::=int Le type des expressions enti`eres

|string Le type des chaˆınes de caract`eres

1∗τ2 Le type des paires

1→τ2 Le type des fonctions

La pr´ec´edence des op´erations arithm´etiques et habituelle, l’appel de fonction est associatif `a gauche et a la mˆeme pr´ec´edence que l’acc`es aux champs d’une paire, et cette pr´ec´edence est plus ´elev´ee que celle des op´erateurs infixes (i.e. comme en Haskell).

Une partie importante de la syntaxe ci-dessus n’est que du sucre syntaxique.

Par exemple, les fonctions n’ont en r´ealit´e qu’un seul argument: la syntaxe offre la possibilit´e de d´eclarer plusieurs arguments, mais ce n’est que du sucre syntax- ique pour des d´efinitions en formecurried. Plus pr´ecis´ement, les equivalences suivantes sont vraies:

letx:τ=e1 ine2 ⇐⇒ letx= (e1:τ)in e2 letf args : τ=e1 ine2 ⇐⇒ letf args= (e1:τ)in e2

letf args=e1 ine2 ⇐⇒ letf =fnargs⇒e1 ine2 fnarg args⇒e ⇐⇒ fn arg⇒fnargs⇒e

Dans l’ensemble c’est un langage similaire `a celui du TP1, mais avec une syntaxe diff´erente et avec des annotations de type. Le let autorise aussi la r´ecursion mutuelle.

La s´emantique statique est standard, et elle est d´ecrite formellement dans la figure 1. L’environnement de type Γ est une liste associative qui associe `a chaque

(3)

Γ ` n : int

Γ(x) =τ Γ ` x : τ

Γ ` e : τ Γ ` (e:τ) : τ Γ ` e1 : τ1 Γ ` e2 : τ2

Γ ` (e1, e2) : τ1∗τ2

Γ ` e : τ1∗τ2

Γ ` #1e : τ1

Γ ` e : τ1∗τ2

Γ ` #2e : τ2 Γ ` e1 : int Γ ` e2 : int

Γ ` e1(+| − | ∗ |/)e2 : int Γ, x:τ1 ` e : τ2

Γ ` fn (x:τ1)⇒e : τ1→τ2

Γ ` e1 : τ1→τ2 Γ ` e2 : τ1

Γ ` e1 e2 : τ2

Γ ` e1 : int Γ ` e2 : τ Γ ` e3 : τ Γ ` if e1then e2elsee3 : τ

Γ, x11, ..., xnn ` ei : τi Γ, x11, ..., xnn ` e : τ Γ ` letx1=e1;...;xn=en ine : τ

Figure 1: R`egles de typage deµML

variable son type. La notation Γ, x:τ repr´esente un nouvel environnement qui est semblable `a Γ sauf qu’il associe `a xle typeτ. La notation Γ(x) =τ signifie que x est associ´e `a τ dans Γ. Le jugement not´e Γ ` e : τ signifie que l’expression e a un type τ lorsqu’elle est dans un environnement statique Γ.

Finalement chaque r`egle de typage est not´ee conclusionpr´emisses et signifie que si hacune des pr´emisses sont v´erifi´ees, alors la conclusion est aussi v´erifi´ee. Par exemple, la derni`ere r`egle indique que le type d’une expression let, est le type de sa sous-expressione. Elle indique aussi que cette sous-expressionedoit ˆetre typ´ee dans un environnement statique o`u lesxi est li´e au type deei. Finalement elle indique aussi que lesei sont aussi typ´es dans un environnement qui est ´etendu avec des liens pourx1...xn, ce qui refl`ete justement le fait que celetautorise les d´efinitions r´ecursives et que donc la port´ee de xi inclut non seulement emais aussi lesei.

Ceci dit, le code fourni s’occupe d´ej`a de v´erifier les types, donc vous n’avez pas `a vous en pr´eoccuper.

Vu que le langage est typ´e statiquement, il utilise n´ecessairement la port´ee statique. De plus, quoique cela n’influence pas votre travail, vous pouvez pr´esumer que les param`etres sont pass´es par valeur.

3 Le code fourni

Le code fourni se r´eparti en plusieurs fichiers:

• alist.cetalist.h: un module tr`es simple de listes associatives simple-

(4)

ment chaˆın´ee.

• hash.cet hash.h: un module de tables de hachage.

• type.c et type.h: un module qui d´efini des types et des fonctions pour construire et manipuler les typesτ.

• exp.c et exp.h: un module qui d´efini des types et des fonctions pour construire et manipuler des expressionse.

• lex.l et parse.y: l’analyseur lexical et l’analyseur syntaxique, d´efinis avec l’aide des outilslexetyacc.

• uml.c: la fonction principale du programme qui lit les fichiers pass´es en param`etre, les analyses, v´erifie leur type, et finalement les r´e-imprime avec le r´esultat de la v´erification de type.

• Makefile: les r`egles de compilation pourmake.

Voil`a un exemple de session o`u j’ai extrait les fichiers fournis, j’ai compil´e le programme, et je l’ai utilis´e sur un test trivial. L’ex´ecutable g´en´er´e s’appelle uml:

% tar zxpf tp3.tar.gz

% cd tp3

% make

lex -olex.c lex.l

yacc -v -d -o parse.c parse.y yacc: 10 reduce/reduce conflicts.

cc -Wall -g -c -o lex.o lex.c

lex.c:1115: warning: ‘yyunput’ defined but not used cc -Wall -g -c -o parse.o parse.c

cc -Wall -g -c -o exp.o exp.c cc -Wall -g -c -o uml.o uml.c cc -Wall -g -c -o type.o type.c cc -Wall -g -c -o hash.o hash.c cc -Wall -g -c -o alist.o alist.c

cc -Wall -g -o uml lex.o parse.o exp.o uml.o type.o hash.o alist.o

% echo "1;" | ./uml Type error: 1

%

L’analyseur syntaxique ´elimine tout le sucre syntaxique pour vous, et g´en`ere un arbre de syntaxe abstraite. Cet arbre de syntaxe abstraite est d´efini dans le fichier principal exp.c. Une partie importante d’un ASA est comment sont repr´esent´es les identificateurs. Dans notre cas, les identificatuers sont sim- plement repr´esent´es par des chaˆınes de caract`eres, mais la comparaison entre identificateurs utilise la comparaison de pointeurs au lieu de la comparaison de chaˆınes: deux identificateurs de mˆeme nom ne sont pas forc´ement ´egaux.

Quelques fonctions importantes:

(5)

• exp print: un “pretty”-printer tr`es simple. Les identificateurs sont im- prim´es avec un suffixe<xxx> qui indique leur adresse pour qu’on puisse facilement distinguer les identificateurs de mˆeme nom.

• exp check: calcule et v´erifie le type d’une expression.

• exp unique vars: renouvelle chaque identificateur pour qu’il soit unique.

E.g. tranforme

letxh12i= 1in letxh12i= 2 inxh12i en

letxh27i= 1in letxh78i= 2 inxh78i.

Cela a l’avantage de r´eduire le risque de capture de nom lorsqu’on manipule le code, par exemple lorsqu’on le d´eplace. De plus, cela simplifie la gestion m´emoire puisque ces nouveaux identificateurs sont garantis “frais”, donc ils ne sont utilis´es nulle part ailleurs et peuvent par cons´equent ˆetre lib´er´es plus facilement.

4 Ce que vous devez faire

Vous avez deux parties `a coder:

• d’abord il faut coder la fonctionexp freedansexp.c qui lib`ere l’espace m´emoire utilis´e par une expression. Pour cela, il vous faudra utiliser la fonctiontype freequi s’occupe de lib´erer l’espace occup´e par une expres- sion de type.

• ensuite il faut compl´eter la fonction exp optimize qui doit faire de la propagation de constantes et de la substitution d’argument, qui ensemble font ce qui s’appelle duinlining. Pour cela vous devrez entre autre coder la fonctionexp copy.

4.1 Lib´ erer la m´ emoire

Cette partie du TP est la plus simple. Il vous faudra simplement vous assurer que vous avez correctement lib´er´e toute la m´emoire utilis´ee par l’expression, et pas plus. Sur les machines GNU/Linux vous pouvez utiliser la fonctionalit´e deMALLOC TRACE qui vous permet de voir les blocs que le programme n’a pas lib´er´es. Note: certains de ces blocs sont hors de votre contrˆole (e.g. ceux utilis´e de mani`ere interne par l’analyseur lexical et l’analyseur syntaxique), donc c’est normal simtracevous dit qu’il y a encore des blocs non lib´er´es. Pour plus d’info surMALLOC TRACEet mtrace, voyez la documentation online de GNU libc. En bref, dans uml.c d´ecommentez le #define IFT2030 MTRACE, et ensuite faire make runmtrace.

(6)

4.2 Optimisation

Vous devez compl´eter la fonctionexp optimizequi doit faire deux op´erations:

la propagation de constantes et la substitution d’arguments. Pour cela vous devrez coder la fonctionexp copy.

La propagation de constantes est une optimisation qui remplace une variable par sa valeur, si cette valeur est connue. Par exemple:

letxh27i= 1inxh27i+ 2 ⇒ letxh27i= 1in1 + 2

Elle s’applique non seulement aux constantes enti`eres mais aussi aux chaˆınes de caract`eres, aux variables, et aux petites fonctions (celles annot´ees inlinable).

La fonctionexp copiable pqui d´etermine si une expression peut ˆetre propag´ee par la propagation de constantes est fournie.

Cette optimisation est g´en´eralement combin´ee avec d’autres optimisations telle que l’´elimination de code mort (qui enl`everait la variable xh27i) ou le constant foldingqui remplacerait le 1 + 2 par 3. L’´elimination de code mort est fournie. Dans ce TP nous ne nous concentrerons `a la place sur l’inlining: une fois qu’une fonction est copi´ee `a l’endroit o`u elle est appel´ee, on peut substituer les arguments actuels pour les arguments formels.

Par exemple, avant d’appelerexp optimize, le code source:

let scaledadd (x:int) (y:int) = x + y * 4 in scaledadd 5 6;

a ´et´e transform´e en:

(let ((scaledadd’<c6b>

(fn [x<f43> : int, y<ebb> : int]

(app + x<f43> (app * y<ebb> 4)))) (scaledadd<a63>

(fni x<f13> : int (fni y<e7b> : int

(app scaledadd’<c6b> x<f13> y<e7b>))))) (app (app scaledadd<a63> 5) 6))

Remarquer que la fonctionscaledadda ´et´e divis´ee en deux: une fonctionscaledaddha63i qui est curried comme dans le code source et qui est marqu´ee inlinable (ce qui explique l’usage de fni au lieu de fn) et qui appelle une autre fonction scaledadd’hc6bi qui elle prend deux arguments. La fonction scaledaddha63i s’appelle ununcurry wrapper.

Le code deexp optimizequi vous allez ´ecrire devrait ˆetre capable d’effectuer les ´etapes suivantes. D’abord propagation de la constantescaledaddha63i:

(let ((scaledadd’<c6b>

(fn [x<f43> : int, y<ebb> : int]

(app + x<f43> (app * y<ebb> 4)))) (scaledadd<a63>

(fni x<f13> : int (fni y<e7b> : int

(7)

(app scaledadd’<c6b> x<f13> y<e7b>))))) (app (app (fni x<a54> : int

(fni y<c21> : int

(app scaledadd’<c6b> x<a54> y<c21>))) 5)

6))

Notez que les variables d´eclar´ees dans le code copi´e doivent ˆetre renomm´ees (renommageα) pour ´eviter des probl`emes de capture de noms. Apr`es cela, une phase d’´elimination de code mort transforme le code comme suit:

(let ((scaledadd’<c6b>

(fn [x<f43> : int, y<ebb> : int]

(app + x<f43> (app * y<ebb> 4))))) (app (app (fni x<a54> : int

(fni y<c21> : int

(app scaledadd’<c6b> x<a54> y<c21>))) 5)

6))

Puis substitution des arguments:

(let ((scaledadd’<c6b>

(fn [x<f43> : int, y<ebb> : int]

(app + x<f43> (app * y<ebb> 4))))) (app (let ((x<f13> 5))

(fni y<e7b> : int

(app scaledadd’<c6b> x<f13> y<e7b>))) 6))

Puis propagation de constante de nouveau:

(let ((scaledadd’<c6b>

(fn [x<f43> : int, y<ebb> : int]

(app + x<f43> (app * y<ebb> 4))))) (app (let ((x<f13> 5))

(fni y<e7b> : int

(app scaledadd’<c6b> 5 y<e7b>))) 6))

Puis ´elimination de code mort:

(let ((scaledadd’<c6b>

(fn [x<f43> : int, y<ebb> : int]

(app + x<f43> (app * y<ebb> 4))))) (app (fni y<e7b> : int

(app scaledadd’<c6b> 5 y<e7b>)) 6))

(8)

Suite `a quoi une substitution d’arguments donne:

(let ((scaledadd’<c6b>

(fn [x<f43> : int, y<ebb> : int]

(app + x<f43> (app * y<ebb> 4))))) (let ((y<e7b> 6))

(app scaledadd’<c6b> 5 y<e7b>)))

Puis propagation de constante + ´elimination de code mort:

(let ((scaledadd’<c6b>

(fn [x<f43> : int, y<ebb> : int]

(app + x<f43> (app * y<ebb> 4))))) (app scaledadd’<c6b> 5 6))

On obtient donc finalement une version efficace du code source, o`u la fonction et son appel ont ´et´euncurried, i.e. au lieu de passer les deux arguments un `a la fois, ils sont pass´es directement ensemble.

Notez comme la fonctionexp optimizeex´ecute de mani`ere it´erative la fonc- tionexp deadcodeet la fonctionexp optimize. L’ordre exact des op´erations ci-dessus d´epend de d´etails de comment vous allez implanter l’optimisation de propagation de constante et de substitution des arguments, donc il se peut que dans votre cas certaines ´etapes soient combin´ees, ce qui ne peut ˆetre que b´en´efique.

Bien sˆur dans cette deuxi`eme partie du TP, il faut aussi faire attention `a correctment g´erer la m´emoire: ne pas oublier de lib´erer tout ce qui doit l’ˆetre.

5 Notes

Vous devez remettre deux fichiers: exp.cet rapport.pdf.

Les commandes pour remettre ces fichier sont les suivantes: pour la premi`ere partie:

% remise ift2030 tp2 exp.c

puis pour la deuxi`eme:

% remise ift2030 tp2 rapport.pdf exp-final.c

• Vous pouvez bien sˆur d´efinir de nouvelles fonctions, mais vous ne devriez pas modifier de fonctions autres que celles mentionn´ees. Vu que vous n’allez remettre queexp.c, il est ´evident que vous ne pouvez pas changer les autres fichiers.

• Tout usage de mat´eriel (code ou texte) emprunt´e `a quelqu’un d’autre (ou trouv´e sur le web) doit ˆetre dˆument mentionn´e, sans quoi cela sera consid´er´e comme du plagiat.

(9)

• Chaque ligne de code doit faire moins de 80 caract`eres. Tout d´epassement sera consid´er´e comme une erreur.

• Votre code doit compiler avecgcc -Wallsans g´en´erer plus d’avertissement que le code fourni.

• V´erifiez la page web du cours, pour d’´eventuels errata, et d’autres indica- tions suppl´ementaires.

Références

Documents relatifs

Les trois fa¸ cons principales de calculer des ´ ecarts types et les intervalles de confiance pour les changements pr´ edits : par l’utilisation de la matrice variance-covariance

R´ esum´ e – Cet article pr´ esente une m´ ethodologie d’identification du comportement de mousses polym` eres hyper´ elastiques ` a partir de mesures de champs par corr´

Quelle est la proportion de personnes consultées dans ce sondage ayant affirmé être insatisfaits de l’administration Plante en lien avec les taxes?. [ ]

• Faute avou´ ee est ` a moiti´ e pardonn´ ee: si votre code s’´ ecarte du comportement stipul´ e par la donn´ ee, il est pr´ ef´ erable de le mentionner et expliquer dans

Le travail consiste ` a utiliser le programme fourni pour mesurer la performance de la hi´ erarchie m´ emoire d’une machine dans diff´ erentes circonstances, et ensuite expliquer les

Votre première tâche sera d'écrire une fonction s2l qui va éliminer le sucre syntaxique, c'est à dire faire l'expansion des formes de gauche (présumément plus pratiques pour

Connecter ces processus via des pipes pour faire des pipelines: ˆ etre capa- ble d’ex´ ecuter des commandes comme “find -name Makefile | xargs grep ch”.. Tout cela bien sˆ ur

Pour ce TP, vous devez impl´ ementer en C l’algorithme du banquier, un algo- rithme qui permet de g´ erer l’allocation des diff´ erents types des ressources, tout en ´ evitant