Utiliser CodeDom pour se faire un compilateur

Le framework .NET expose des classes permettant d’accéder au compilateur C#. Dans ce billet, nous verrons utiliser ces classes afin de créer notre propre compilateur C#.

Interface graphique

Nous allons commencer par réaliser l’interface graphique de notre application en WPF. Ouvrez Visual Studio et sélectionnez Fichier – Nouveau projet, puis choisissez Application WPF et appelez le « Compilateur » :

1

Nous allons ensuite ajouter une TextBox dans notre fenêtre principale. Celle-ci nous servira à écrire le code qui devra être compilé. Puis nous ajouterons un TabControl contenant deux TabItem. Ces deux TabItem serviront à afficher le résultat de la compilation et la liste des erreurs relatives au code. Nous ajouterons également un Button afin de générer le code et l’exécuter si la génération s’est déroulée avec succès. Votre fenêtre devrait normalement (ou à peu de choses près) ressembler à ceci :

2

A présent, nous pouvons passer au chapitre suivant ;)

Implémentation du code

Présentation de la classe CSharpCodeProvider

Comme je vous le disais en introduction, le framework .NET contient des classes permettant d’accéder aux instances du générateur de code et donc de pouvoir créer son propre compilateur. Dans le cadre de cet article, nous allons nous intéresser de plus près à la classe CSharpCodeProvider.

Cette classe est une classe dérivée de la classe de base CodeDomProvider et fournit l’accès au compilateur de code C# (A noter qu’il existe l’équivalent pour VB et JScript).

Compilation du code

En premier lieu, nous allons ajouter au code behind, les instructions using suivantes :

using System.CodeDom.Compiler;
using Microsoft.CSharp;

Nous allons ensuite créer l’événement Click du Button Build en double-cliquant sur celui-ci depuis le fichier .xaml puis implémenter sa logique. Tout d’abord, nous allons effacer le contenu des TextBox des onglets :

// Cleaning txtItemOutput and txtItemErrors
txtItemOutput.Text = "";
txtItemErrors.Text = "";

On va ensuite créer une instance de CodeDomProvider pour le langage C# :

// Create instance of CodeDomProvider
CodeDomProvider provider = CSharpCodeProvider.CreateProvider("CSharp");

La prochaine étape sera de préciser que nous souhaitons générer un fichier exécutable et spécifier  son nom. Pour y parvenir, nous devons utiliser la classe CompilerParameters représentant la liste des paramètres d’un compilateur :

// Name of .exe file
string Output = "MyProgram.exe";

CompilerParameters parameters = new CompilerParameters();
// Specify we want an .exe file instead of a .dll
parameters.GenerateExecutable = true;
// Name of output assembly
parameters.OutputAssembly = Output;

On passe maintenant à la partie « Compilation » en utilisant la méthode CompileAssemblyFromSource de l’objet provider. Cette méthode permet de compiler un assembly et renvoie un objet de type CompilerResults contenant le résultat de la compilation. Elle prend deux objets en paramètres. Tout d’abord un objet de type CompilerParameters que nous avons créé précédemment puis un tableau de string contenant les sources à compiler.

CompilerResults results = provider.CompileAssemblyFromSource(parameters, txtCodeSource.Text);

La dernière étape consiste à vérifier si l’objet results contient des erreurs de compilation et le cas échéant, à l’indiquer dans l’onglet Output et afficher le détail dans l’onglet Errors :

if (results.Errors.Count > 0)
{
    txtItemOutput.Text = results.Errors.Count + " error(s). See Errors Menu.";

    foreach (CompilerError CompErr in results.Errors)
    {
        txtItemErrors.Text = txtItemErrors.Text +
                    "Line number " + CompErr.Line +
                    ", Error Number: " + CompErr.ErrorNumber +
                    ", '" + CompErr.ErrorText + ";" +
                    Environment.NewLine + Environment.NewLine;
    }
}

Exécution du code

Afin de pouvoir exécuter votre code, une nouvelle instruction using doit être ajoutée à votre .xaml.cs :

using System.Diagnostics;

Cette instruction nous permet d’accéder à la classe Process. Nous allons ajouter une condition else gérant le cas où la compilation  s’est déroulée sans erreurs :

else
{
    //Successful Compile
    txtItemOutput.Text = "Compile successful!";
    Process.Start(Output);
}

C’est aussi simple que ça :)

Allez ! On se fait le classique Hello World ? :)

Exécuter votre programme et copier/coller le code suivant dans la TextBox source :

using System;

namespace HelloWorld
{
    class HelloWorld
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            Console.ReadLine();
        }
    }
}

Normalement, vous devriez obtenir ceci :

3

4

La compilation et l’exécution se sont bien déroulées et en vérifiant dans le dossier bin/Debug de votre projet, un fichier .exe a bien été généré. Vous pouvez également modifier le code source de façon à générer une erreur et voir comment se comporte le programme.

Il ne vous reste plus qu’à l’améliorer à votre sauce en ajoutant d’autres fonctionnalités telles que la coloration syntaxique, la tabulation, etc…

A venir prochainement, un article sur Roslyn

Pour marque-pages : permalien.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>