Les commentaires.
J'ai remarqué dans l'exemple précédent "// j'imprime sur la sortie standard". Que cela veut-il dire ?
Ceci est un commentaire. En effet, vous pouvez laisser dans votre code des explications (c'est d'ailleurs très fortement recommandé). Il existe plusieurs formes de commentaires :
Commentaire sur une ligne
// Mon commentaire
/// Ceci est une documentation
Commentaires multi-lignes
/*
 Ceci est un commentaire
/*
 * Ceci est un commentaire
/+
 Ceci est un commentaire
/+
 + Ceci est un commentaire
/**
 Ceci est une documentation
/**
 * Ceci est une documentation
/++
 + Ceci est une documentation
Vous remarquerez qu'il est parfois écrit « documentation » au lieu de « commentaire ». En effet, on peut documenter son code. Ainsi, un programme externe va lire votre code source et générer automatiquement la documentation. Pour les connaisseurs, c'est le même principe que la javadoc ou doxygen.
Nous y reviendrons plus loin dans ce chapitre.
Les types primitifs.
Note 1 : les valeurs suivantes ont été obtenues sur un système 64 bits.
Note 2 : vous pouvez générer ces résultats avec le programme D pour connaitre la taille des types.
Les opérateurs arithmétiques.
+ permet d'additionner deux variables numériques.
- permet de soustraire deux variables numériques.
/ permet de diviser deux variables numériques.
% permet de renvoyer le reste de la division euclidienne de deux variables de type numérique, cet opérateur s'appelle le modulo.
Par exemple :
import tango.io.Stdout;
void main(){
 uint a = 2;
 uint b = 2;
 Stdout.formatln("une addition: {} + {} = {}", a, b, a+b);
 Stdout.formatln("une soustraction: {} - {} = {}", a, b, a-b);
 Stdout.formatln("une multiplication: {} x {} = {}", a, b, a*b);
 Stdout.formatln("une division: {} / {} = {}", a, b, a/b);
 Stdout.formatln("le modulo: {} % {} = {}", a, b, a%b);
Une histoire d'incrémentation et décrémentation.
Dans la même catégorie, il existe l'incrémentation et la décrémentation :
Pour cela, il y a plusieurs façons de le faire. Prenons le cas de l'incrémentation :
int a = 2;
a = a + 1;
a += 1;
a++;
Vous remarquez que les 2 dernières formes sont plus rapides à écrire (oui, le programmeur est un fainéant).
Y a t-il une différence entre ++a et a++ ?
Oui, il y en a une et elle est subtile :
Par exemple :
import tango.io.Stdout;
void main(){
 uint a = 2; 
 uint b = 1;
 Stdout.formatln("une incrémentation: {} + {} = {}", a, b, a++);
 a = 2;
 Stdout.formatln("une incrémentation: {} + {} = {}", a, b, ++a);
 a = 2;
 Stdout.formatln("une décrémentation: {} - {} = {}", a, b, a--);
 a = 2;
 Stdout.formatln("une décrémentation: {} - {} = {}", a, b, --a);
Autres raccourcis.
On peut également utiliser les raccourcis pour la multiplication, la division et le reste de la division euclidienne.
un court exemple :
uint a = 5;
a *= 2;
a /= 2;
a %= 2;
Attention.
Je vous mets en garde sur le type utilisé. Ce dernier peut avoir des conséquences graves ! En effet, jusqu'ici on a utilisé le type uint et nos résultats étaient des entiers. Mais ceci n'est pas systématiquement vrai. Par exemple, diviser 1 par 3 donne un résultat décimal ne pouvant pas correspondre à un entier positif (uint). Par conséquent, vous devez utiliser un autre type plus approprié, comme le type float ou double :
double a = 1;
a /=3; // a vaut 0.33333333
int b = 1;
int c = 3;
double d = b / c; // d vaut 0.33333333
Les opérateurs de comparaison.
Il est fréquent dans un programme que l'on ai de besoin de comparer. Pour cela, en D il est possible de tester différents cas :
3 == 3; // cette expression retournera vrai
3 == 4; // cette expression retournera faux
int a = 4;
3 != a; // 3 est différent de 4 donc cette expression retournera vrai
a || b // si l'une des expressions est vraie, l'expression globale sera vraie
a && b // si l'une des expressions est fausse, l'expression globale sera fausse
a < b // savoir si a est strictement plus petit que b
a <= b // savoir si a est plus petit ou égal à que b
a > b // savoir si a est strictement plus grand que b
a >= b // savoir si a est plus grand ou égal à b
a is b // savoir si a est identique à b
a !== b // savoir si a n'est pas identique à b
Test d'identité.
Les comparateurs d'identités sont particuliers et méritent plus d'explications.
Si l'on compare :
int[1] a = 2;
int[1] b = a;
a is b; // retournera vrai
Lorsque l'on compare des types avec ce comparateur, il agit comme si c'était le comparateur ==
Personne jean = new Personne("jean");
Personne paul = new Personne("paul");
jean is paul; // retournera faux
Lorsque l'on compare des objets entre eux, ce comparateur va dire si oui ou non c'est le même objet qui est référencé.
On reviendra plus tard sur les références, gardez les à l'esprit et n'hésitez pas à revenir dessus.
Le comparateur !== est la négation du comparateur === donc
Personne jean = new Personne("jean");
Personne paul = new Personne("paul");
jean !is paul; // retournera vrai
Les conditions.
Nous avons vu les opérateurs de comparaison : maintenant, nous allons les utiliser avec les conditions. Rien de plus simple ! Commençons de suite.
Avec les mots clés if et else.
int a = 2;
if ( a == 2 ){ // test une égalité avec l'opérateur == , si a vaut 2
 Stdout("la variable a vaut bien 2").nl;
else if ( a == 3){ // sinon si la variable a vaut 3
 Stdout("la variable a vaut bien 3").nl;
else{ // sinon (pour tous les autres cas)
 Stdout.formatln("la variable a vaut {}",a);
C'était un exemple pour vous dégourdir les méninges. Complexifions légèrement avec divers exemples d'utilisation :
int a = 2;
int b = 3;
if ( a == 2 && b == 3 ){ // si a vaut 2 et b vaut 3. Les 2 conditions doivent être vraies pour rentrer dans le bloc
 Stdout.formatln("la variable a vaut {} et la variable b vaut {}", a, b);
if ( a == 2 || b ==3 ){ // si a vaut 2 ou bien si b vaut 3. Au moins une des 2 conditions doit être vraie pour rentrer dans le bloc
 Stdout.formatln("la variable a vaut {} et la variable b vaut {}", a, b);
if ( a > 1 && b >= 3 ){ // si a est strictement plus grande que 1 et b plus grande ou égale à 3. Les 2 conditions doivent être vraies pour rentrer dans le bloc
 Stdout.formatln("la variable a vaut {} et la variable b vaut {}", a, b);
if ( a <= 2 || b < 3){ // si a est plus petite ou égale à 2 ou bien si b est strictment plus petite que 3. Au moins une des 2 conditions doit être vraie pour rentrer dans le bloc
 Stdout.formatln("la variable a vaut {} et la variable b vaut {}", a, b);
Avec les mots clés switch et case.
Vous avez vu précédemment la possibilité d'imbriquer des "si" - "sinon" de la manière suivante :
int a = 4;
if ( a == 0 ){
else if ( a == 1 ){
else if ( a == 2 ){
else if ( a == 3 ){
else if ( a == 4 ){
else {
Sachez qu'il existe une manière plus élégante d'écrire cela à l'aide des mots clés "switch" et "case" :
int a = 4;
switch (a){ // on met la variable à tester
 case 1: // cas où la valeur est 1
 break
 case 2: // cas où la valeur est 2
 break
 case 3: // cas où la valeur est 3
 break
 case 4: // cas où la valeur est 4
 break
 default: // cas où la valeur est différente
Pourquoi retrouve-t-on break à chaque fois ?
Admettons, pour imager, 2 choses :
D'après l'exemple précédent, on entrerait dans le bloc à partir du cas 3 et on effectuerait tous les cas suivants, c'est à dire ici le cas 4 et le cas par défaut. Dans la majeure partie des cas, on n'a pas besoin d'exécuter 2 règles, c'est pour cela que l'on met l'instruction break afin qu'il quitte après avoir effectué son traitement.
Un dernier exemple du même type pour la route :
int a = 1;
switch (a) { // on met la variable à tester
 case 1: // cas où la valeur est 1
 case 2: // cas où la valeur est 2
 case 3: // cas où la valeur est 3
 break
 case 4: // cas où la valeur est 4
 break
 default: // cas où la valeur est différente
Ici, on va rentrer dans le cas 1, 2 et 3 puis sortir.
Ce comportement est similaire en C et en C++. Mais en D, on peut également utiliser des chaînes de caractères :
char[] prenom = "jonathan";
switch (prenom){ // on met la variable à tester
 case "jonathan": // cas où la valeur est "jonathan"
 break
 case "jean": // cas où la valeur est "jean"
 break
 case "paul": // cas où la valeur est "paul"
 break
 case "remi": // cas où la valeur est "remi"
 break
 default: // cas où la valeur est différente
Les tableaux.
Déclaration.
Il y a 5 façons de déclarer un tableau :
Les pointeurs.
int* p;
Ceci est un simple pointeur vers des données., il représente la même chose qu'en C.
Attention cependant, contrairement au C, le code suivant
int* p1, p2;
déclare deux pointeurs vers des entiers, alors qu'en C, il déclare un pointeur et un entier ! Pour cette raison, il est d'usage de toujours rattacher l'astérisque au type de données plutôt qu'au nom de la variable.
Les tableaux statiques.
int[3] s;
Un tableau statique est un tableau dont on spécifie la taille lors de sa déclaration, taille qui ne changera plus. Ici, on crée un tableau dans lequel on peut stocker 3 entiers. La taille d'un tableau statique est fixée au moment de la compilation.
Par exemple :
int[3] s;
s[0] = 50;
s[1] = 24;
s[2] = 98
Les tableaux dynamiques.
int[] a;
Un tableau dynamique est un tableau dont la taille peut varier. Lors de sa déclaration, on ne spécifie pas sa taille. En fait, c'est le ramasse-miette (garbage collector) qui gère ce tableau au moyen d'un pointeur.
Exemple :
int[] a;
a.length = 2; // on donne une taille de 2
a[0] = 5;
a[1] = 8;
a.length = a.length + 5 // ici 2+5 = 7 soit la nouvelle taille du tableau
a[2] = 5;
a[3] = 7;
a[4] = 9;
a[5] = 3
a[6] = 1;
Il est conseillé de faire le minimum de redimensionnements de tableau possibles afin de garder de bonnes performances. Ainsi, on évitera :
int[] a;
for ( i = 0 , i < 50, i++) {
 a.length = a.length + 1;
 a[i] = 0;
On utilisera de préférence :
int[] a;
for ( i = 0 , i < 50, i++){
 if (a.length == i) {
 a.length = a.length * 2; // si la taille du tableau est égale à l'indice i, on double sa taille;
 a = 0;
a.length = i; // Afin d'économiser la mémoire, on ajuste exactement la taille du tableau au besoin soit la valeur de l'indice i
Les tableaux associatifs.
int[char[]] x;
Un tableau associatif est un tableau où l'on associe 2 valeurs ensemble. Ici, on associe une chaîne de caractères à un entier.
Astuce: pour comprendre ce que que représente un tableau associatif, je vous conseille de le lire de la droite vers la gauche. Soit :
Le tableau associatif x contient des chaînes de caractères qui sont associées à un entier
Exemple :
int[char[]] x;
x["pomme"] = 2;
x["poire"] = 5;
x["orange"] = 7;
Dans l'exemple ci-dessus, on associe un fruit à un nombre (pratique pour connaitre la quantité restante de chaque fruit).
Le slicing.
Le slicing est une technique particulière qui permet de copier une série d'éléments d'un tableau dans un autre. Voici un exemple de cette technique :
int[10] a = [1,2,3,4,5,6,7,8,9,10]; // déclare un tableau de 10 entiers
int[] b; // déclare un tableau dynamique
int[] c; // déclare un tableau dynamique
int[3] d; // déclare un tableau statique de 3 éléments
b = a[1..3]; // le fameaux slicing, on copie ici les éléments des indices 1 à 3 dans le tableau b. Rapel: le 1er indice est le 0 a[0]
c = a[4..$]; // ici on copie tous les éléments à partir de l'indice 4 jusqu'à la fin
d[0..2] = 5; // ici on assigne la valeur 5 à tous les éléments du tableau. Cela équivaut à d[0] = 5 d[1] = 5 d[2] = 5
Concaténation de tableaux.
int[10] a = [1,2,3,4,5,6,7,8,9,10]; // déclare un tableau de 10 entiers
int[10] b = [11,12,13,14,15,16,17,18,19,20]; // déclare un tableau de 10 entiers
int[] c;
c = a ~ b; // soit c contient 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
On peut combiner le slicing et la concaténation :
int[10] a = [1,2,3,4,5,6,7,8,9,10]; // déclare un tableau de 10 entiers
int[10] b = [11,12,13,14,15,16,17,18,19,20]; // déclare un tableau de 10 entiers
int[] c;
c = a ~ b[0..5]; // soit c contient 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
Les matrices.
Peu de langages supportent nativement les matrices, mais le langage D en fait partie.
Qu'est-ce qu'une matrice ?
Mieux qu'un long discours voici un exemple :
Ceci est une matrice de 3 colonnes par 4 lignes :
uint[3][4] matrix; // déclaration de la matrice tous les élément de la matrice sont à 0
foreach (ligne; matrix)
 ligne[0..$] = 1;// on remplit la matrice de 0 en utilisant le slicing, c'est pratique !
Les chaînes de caractères.
Les langages de programmation doivent bien gérer les chaînes de caractères. Le C et le C++ ne sont pas très bons pour cela. La première difficulté est de gérer la mémoire, les traitements temporaires, de constamment scanner les chaînes de caractères pour rechercher la terminaison par "\0" et de fixer la taille.
Les tableaux dynamiques en D suggèrent la solution la plus évidente. Une chaîne est simplement un tableau dynamique de caractères. Les chaînes littérales sont juste un moyen facile d'écrire des tableaux de caractères.
char[] str = "Le D c'est génial"; // déclaration et initialisation
char[] str1 = str.dup; // copie de la chaîne de caractères
str += " et je l'ai adopté"; // on ajoute à la suite de la chaîne str
char str2[] = "Vive le D";
char str3 = str ~ str2; // on concatène str et str2, grâce au ~ et on stocke le tableau résultant dans str3
Par défaut les chaînes de caractère sont encodées en utf8. Il existe également les types:
Si une chaîne est ambigüe et peut correspondre à plusieurs types, il faut préciser.
Si on veut de l'UTF-16, on peut faire un cast (voir « Le transtypage (cast) ») :
(wchar [])"J'aime le D";
Ou si on veut de l'UTF-32 :
(dchar[])"J'aime le D";
char c;
wchar u;
dchar a;
c = "b"; // le caractère b (UTF-8) est assigné à c
u = "b" // le caractère b (UTF-16) est assigné à u
a = "b" // le caractère b (UTF-32) est assigné à a
u = \n; // un retour à la ligne est assigné à u
Les tableaux associatifs.
Le langage D intègre nativement les tableaux associatifs. Précédemment, vous avez eu un court exemple de leur utilisation. Voici quelques autres exemples :
int[char[]] b; // association d'une chaîne de caractère à un entier
b["pomme"] = 3 // on met 3 pommes
uint nombre = b["pomme"]; // renvoie le nombre de pommes
delete b["pomme"]; // on supprime la clé "pomme"
Dépassement de la taille du tableau.
Le dépassement de la taille limite du tableau constitue une erreur fréquemment rencontrée. Le compilateur vous annoncera « Array index out of bounds ». Vous apprendrez plus loin comment attraper et gérer les exceptions.
Important.
En D 1.x comme dans d'autres langages tels que le Python, les tableaux et les objets sont passés par référence et non par copie.
Qu'est-ce que cela veut dire ?
Pour faire simple, une référence est une entité qui pointe vers son original. Si l'on modifie la référence, cela modifie l'original. C'est un comportement qui permet d'éviter de recopier un tableau (ce qui peut être long) mais qui, si l'on ne fait pas attention, peut générer des erreurs. Gardez bien cela à l'esprit, c'est capital !
Si le besoin d'une copie et non d'une référence se fait sentir, ils vous suffit de la demander avec la propriété dup :
int [5] a = 3; // les 5 colonnes valent 3
int [] b = a; // b est une référence de a, si je modifie b le tableau a sera modifié
int [] c = a.dup; // c est une copie de a, je peux modifier c sans modifier a
Exemple.
import tango.io.Stdout;
void ajoute(uint nombre, uint[] tableau)
 foreach(indice,element;tableau){
 tableau[indice] = element + nombre;
void main()
 uint[] montableau = [1,2,3,4,5,6];
 ajoute(2, montableau);
 Stdout(montableau).nl;
Vous voyez votre tableau a été modifié à votre insu, vous avez sur le terminal :
 [3, 4, 5, 6, 7, 8]
Vous vous retrouvez avec le tableau modifié par la fonction ajoute, si vous ne voulez pas ce comportement vous devez envoyer une copie du tableau, voici en exemple:
import tango.io.Stdout;
void ajoute(uint nombre, uint[] tableau)
 foreach(indice,element;tableau){
 tableau[indice] = element + nombre;
void main()
 uint[] montableau = [1,2,3,4,5,6];
 ajoute(2, montableau.dup);
 Stdout(montableau).nl;
Ce qui donne :
 [1, 2, 3, 4, 5, 6]
Si le besoin d'une copie et non d'une référence se fait sentir, ils vous suffit de la demander avec la propriété dup :
int [5] a = 3; // les 5 colonnes valent 3
int [] b = a; // b est une référence de a, si je modifie b le tableau a sera modifié
int [] c = a.dup; // c est une copie de a, je peux modifier c sans modifier a
Attention.
À partir de la version 2 du langage, les tableaux statiques sont passés par valeur ! Ce changement permet une meilleure vectorisation du code (notamment pour l'utilisation par le compilateur d'instructions comme les SSE) et facilite la programmation concurrente. 
Pour porter du code D1 vers D2 et revenir à l'ancien comportement, il suffira de passer un slice complet du tableau en paramètre, les slices, comme les tableaux dynamiques, étant toujours passés par référence :
// CODE D 2.0 !
int[4] tableauStatique;
int[] tableauDynamique = new int[4];
fonction(tableauStatique); // passage par valeur !
fonction(tableauStatique[]); // avec un slice, on passe par référence, comme en D1
fonction(tableauDynamique); // passage par référence, ça ne change pas entre D1 et D2
Les boucles.
Tant que (while).
import tango.io.Stdout
void main()
 uint = 0;
 while (i < 10)
 Stdout(i).nl;
 i++;
Tant que i est plus petit que 10, on boucle et on imprime sur la sortie standard la valeur courante de i.
Faire tant que (do … while).
Cette boucle est semblable à la précédente, seulement ici on garantit au moins une fois le passage dans la boucle.
import tango.io.Stdout
void main()
 uint i = 10;
 do{
 Stdout(i).nl;
 i++;
 while(i < 10)
Pour (for).
On peut effectuer la déclaration d'une variable, définir les conditions de la boucle et définir une action exécutée à chaque début de boucle (généralement l'incrémentation de cette variable) dans la déclaration de la boucle for :
for (uint i = 0; i < 10; ++i)
 Stdout(i).nl;
Pour chaque (foreach).
uint[5] a = [1,5,4,6,8];
foreach(element;a)
 Stdout(element).nl;
Pour chaque élément de a, on imprime sa valeur sur la sortie standard.
On peut également connaître le nombre d'itérations dans la boucle foreach. Par exemple, connaître le numéro de ligne ou l'indice du tableau en cours de traitement.
uint[5] a = [1,5,4,6,8];
foreach(compteur,element;a) // Notons que element est de même type que a, ici de type uint[] 
 Stdout.formatln("numéro {} valeur {}",compteur, element);
Aller à (goto).
Le goto n'est à utiliser que dans des cas précis. Il ne faut surtout pas en abuser et la plupart du temps les autres types de boucles suffisent. Depuis le temps que je programme je n'ai eu à l'utiliser qu'une seule fois.
Le goto permet d'aller directement à un endroit du code défini par une étiquette :
import tango.io.Stdout;
void main()
 uint i = 0;
 Stdout("Bonjour").nl;
 monEtiquette:
 i++;
 Stdout.formatln("Valeur de i {}", i);
 if ( i < 2 )
 goto monEtiquette;
 Stdout("Fin").nl;
Le transtypage (cast).
En langage D, il existe 2 manières d'effectuer une conversion de type :
La première façon de faire est générique et permet de caster (convertir) tout et n'importe quoi. C'est l'équivalent du dynamic_cast pour les connaisseurs du C++.
La seconde manière est restreinte au type cité dans un chapitre précédent mais est plus sûre.
Exemples :
import module tango.util.Convert;
short a = 1;
float b = 0.5;
int c = to!(int)(a); // on utilise le template nommé "to" provenant du module Convert et on spécifie le type int
int d = cast(int)a; 
double e = to!(double)(b); // on utilise le template nommé "to" provenant du module Convert et on spécifie le type double
double f = cast(double)(b);
On utilise le module Convert uniquement pour utiliser le template "to" (le mot clé cast n'a besoin d'aucun module).
Lire les entrées clavier.
import tango.io.Console;
void main()
 Cout("Entrer votre nom: ")();
 char[] nom = Cin.get;
 Cout("Salut ")(nom).newline;
Demander le nom et l'âge :
import tango.io.Console;
import tango.util.Convert;
import tango.io.Stdout;
void main()
 Cout("Entrer votre nom: ")();
 char[] nom = Cin.get;
 Cout("Entrer votre age: ")();
 uint age = to!(uint)(Cin.get);
 Stdout.formatln("Salut {} tu as donc {} ans", nom , age); 
On doit convertir ce qui a été saisie par l'utilisateur (char[]) en uint.
Parser les arguments de la ligne de commande.
La bibliothèque tango propose un module très pratique pour parser les arguments de la ligne de commande. Il existe un tutoriel en anglais ici. Je vais vous présenter la manière dont je l'utilise :
import text.Arguments : Arguments;
import tango.io.Stdout : Stdout, Stderr;
import tango.text.Regex: Regex;
import monApplication.Parser;
bool verbose = false;
const float numVersion = 0.1;
void verboseMode(char[] message)
 if (verbose)
 Stdout.formatln("\033[0;31m'{}'\033[0;0m",message);
void about()
 Stdout.formatln("monApplication version \033[0;31m'{}'\033[0;0m", numVersion);
 Stdout.formatln("monApplication est un super programme écrit en D.");
void usage(Arguments getopt)
 Stdout.formatln("\033[0;31mUsage:\033[0;0m ./monApplication [options] --input files");
 Stdout.formatln("Options:");
 getopt.help((char[] param, char[] text){Stdout.format("\t--{} {}\n",param, text);});
int main (char[][] args)
 char[] inputFile;
 char[] outputFile;
 /**
 * Definit les options du programme
 auto getopt = new Arguments;
 getopt("help").params(0).aliased('h').help("- Display this message");
 getopt("verbose").params(0).aliased('v').help("- Enable verbose mode");
 getopt("input").params(1).aliased('i').help("- Path to input file");
 getopt("output").params(1).aliased('o').help("- Path to output file");
 getopt("version").params(0).help("- Display metatool version");
 * Parse la ligne de commande
 getopt.parse(args);
 * Active ou non le mode verbeux
 if (getopt("verbose").set)
 verbose = true;
 /**
 * Affiche l'aide si demandé
 if (getopt("help").set)
 usage(getopt);
 /**
 * Affiche la version si demandée
 else if (getopt("version").set)
 about();
 /**
 * Affiche un message d'erreur et quitte le programme si l'option --input n'est pas presente
 else if (!getopt("input").set)
 Stderr.formatln("\033[0;31mWarning:\033[0;0m option --input absent!");
 usage(getopt);
 scope(failure) Stderr.formatln("Programme quit subitement");
 else{
 * Stocke le nom du fichier soumis par l'option --input
 inputFile = getopt("input").assigned[0];
 verboseMode("Input file: "~inputFile);
 * Stocke le nom du fichier soumis par l'option --output
 if (getopt("output").set){
 outputFile = getopt("output").assigned[0];
 else{ // Si l'option --output est absente, il prend le nom du fichier "input" et remplace l'extention par .out
 auto filePattern= new Regex(r"\.[a-zA-Z0-9_]+");
 if (filePattern.test(inputFile)){
 outputFile = filePattern.replaceLast(inputFile,".out");
 else{
 outputFile = inputFile ~ ".out";
 verboseMode("Output file: "~outputFile);
 * Parse le fichier input
 auto parser = new Parser(inputFile);
 parser.parse();
 parser.check();
 scope(exit) Stdout.formatln("quit");
 scope(success) Stdout.formatln("Programme se termine avec succès");
 return 1;