Developpez.com - Eclipse
X

Choisissez d'abord la catégorieensuite la rubrique :


Introduction à XText pour la création d'un langage spécifique à la description de graphe

Date de publication : 28/10/2011. Date de mise à jour : 7/11/2011.

Par Serge BACHMANN (Page perso)
 

Ce tutoriel s'intéresse à l'utilisation du framework Java XText via la plateforme Eclipse pour la création d'un DSL spécifique. Un langage de description de graphe est défini à partir d'un méta langage. Un éditeur syntaxique coloré est créé à partir de ce langage spécifique. Un graphe est édité, on accède à la description du graphe généré.

       Version PDF (Miroir)   Version hors-ligne (Miroir)
Viadeo Twitter Facebook Share on Google+        



0. Pré-requis logiciels
1. Introduction
1.1. Spécification
1.2. Lancer la plateforme
1-3. Installation de XText
1-4. Perspective « Plugin Development »
2. Projet « ... graphemodel »
2-1. Notre grammaire
2-2. Génération
2-3. Edition du fichier MANIFEST
2-4. Le fichier plugin.xml
2-5. Le package « org.eclipse.xtext.example.graphemodel »
3. Projet « ... graphemodel.ui »
3-1. Commande View Model
3-2. Définition du « Handler »
4. Test
4-1. L'éditeur
4-2. La commande « View Model »
5. Une autre grammaire
6. Conclusion


0. Pré-requis logiciels

La version Eclipse utilisée dans ce tutoriel est Eclipse Indigo 3.7.1 en incluant la distribution Eclipse Modeling Tools.


1. Introduction


1.1. Spécification

Construire un éditeur syntaxique d'un graphe.


1.2. Lancer la plateforme

Double cliquer : eclipse.exe ou le raccourci vers cet exécutable si vous l'avez créé dans le répertoire destiné à recevoir les « workspaces ». La plate-forme « Eclipse » est lancée :

On choisi le « Workspace » :

Cliquer « OK ». Fermer la fenêtre « Welcome ».


1-3. Installation de XText

Sélectionner la commande « Help – Install Modeling Components »

Dans « Eclipse Modeling Components Discovery – Eclipse Modeling Components Discovery »

Sélectionner Xtext :

Cliquer « Finish ».

Confirmer l'installation de « XText »

Cliquer « Next > »

Cliquer « Next > »

Accepter la licence :

Cliquer « Finish », Xtext s'installe.

Il faut relancer Eclipse:

Cliquer sur le bouton « Restart Now ».

Nous conserverons le même « Workspace » puis cliquer sur « OK ».


1-4. Perspective « Plugin Development »

Sélectionner la commande « Window – Open Perspective > Other... ». Dans « Open Perspective » sélectionner « Plug-in Development », fermer les vues inutiles ce qui donne :


2. Projet « ... graphemodel »

Sélectionner la commande « File > New > Project... »

Dans « New Project – Select a wizard » sélectionner « Xtext Project »

Cliquer « Next > »

Initialiser: « New Xtext Project – New Xtext Project »

Cliquer « Finish »

Les projets suivants sont créé:

Dans org.xtext.example.graphemodele > src > org.xtext.example le fichier GrapheModel.xtext définit la grammaire de notre langage.

warning Chaque projet contient les répertoires src et src-gen. Nous ne devrons intervenir que sur les répertoires src.

2-1. Notre grammaire

On édite le fichier « GrapheModel.xtext » :

grammar org.eclipse.xtext.example.Graphemodel with org.eclipse.xtext.common.Terminals

generate graphemodel "http://www.eclipse.org/xtext/example/Graphemodel"

Graphe:
   (grapheElements += GrapheElement)*;
GrapheElement:
   Noeud | Arc ;

Arc:
	'Arc'
	'{'
		'nom' name=ID
		'origine' origine= NoeudOrigine
		'extremite' extremite= NoeudExtremite
	'}';

NoeudOrigine:
	reference=[Noeud];
   
NoeudExtremite:
	reference=[Noeud];
   
Noeud:
	'Noeud'
	'{'
		'nom' name=ID
	'}';
Ce qui donne après sauvegarde :


2-2. Génération

Dans le projet « org.xtext.example.graphemodel », sous « src > org.xtext.example » ouvrir : « GenerateGrapheModel.mwe2 ».

Dans l'éditeur faire un clic droit pour faire monter le menu contextuel et sélectionner « Run As > NWE2 Workflow » :

Le message suivant apparaît dans la vue « Console » saisir « y » puis « enter » comme demandé :

0    [main] INFO  lipse.emf.mwe.utils.StandaloneSetup  - Registering platform uri 'E:\ECLIPSE\XText\WORKSPACES\DSL_Graphe'

*ATTENTION*
It is recommended to use the ANTLR 3 parser generator (BSD licence - http://www.antlr.org/license.html).
Do you agree to download it (size 1MB) from 'http://download.itemis.com/antlr-generator-3.0.1.jar'? (type 'y' or 'n' and hit enter)y
Le parser « ANTLR 3 » est installé. Après génération le projet org.xtext.example.graphemodele devient :


2-3. Edition du fichier MANIFEST

Dans le « Plugin manifest Editor » onglet « Overview » modifier le « provider »:

Faire une sauvegarde.

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: org.xtext.example.graphemodele
Bundle-Vendor: LAAS CNRS
Bundle-Version: 1.0.0
Bundle-SymbolicName: org.xtext.example.graphemodele; singleton:=true
Bundle-ActivationPolicy: lazy
Require-Bundle: org.eclipse.xtext;bundle-version="2.0.0";visibility:=reexport,
 org.apache.log4j;bundle-version="1.2.15";visibility:=reexport,
 org.apache.commons.logging;bundle-version="1.0.4";resolution:=optional;visibility:=reexport,
 org.eclipse.xtext.generator;resolution:=optional,
 org.eclipse.emf.codegen.ecore;resolution:=optional,
 org.eclipse.emf.mwe.utils;resolution:=optional,
 org.eclipse.emf.mwe2.launch;resolution:=optional,
 org.eclipse.xtext.util,
 org.eclipse.emf.ecore,
 org.eclipse.emf.common,
 org.antlr.runtime,
 org.eclipse.xtext.common.types
Import-Package: org.apache.log4j,
 org.apache.commons.logging,
 org.eclipse.xtext.xbase.lib,
 org.eclipse.xtext.xtend2.lib
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Export-Package: org.eclipse.xtext.example,
 org.eclipse.xtext.example.services,
 org.eclipse.xtext.example.graphemodel,
 org.eclipse.xtext.example.graphemodel.impl,
 org.eclipse.xtext.example.graphemodel.util,
 org.eclipse.xtext.example.serializer,
 org.eclipse.xtext.example.parser.antlr,
 org.eclipse.xtext.example.parser.antlr.internal,
 org.eclipse.xtext.example.validation

2-4. Le fichier plugin.xml


<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin>
  <extension point="org.eclipse.emf.ecore.generated_package">
    <package 
       uri = "http://www.eclipse.org/xtext/example/Graphemodel" 
       class = "org.eclipse.xtext.example.graphemodel.GraphemodelPackage"
       genModel = "org/eclipse/xtext/example/Graphemodel.genmodel" />
  </extension>
</plugin>

2-5. Le package « org.eclipse.xtext.example.graphemodel »

Dans le projet « org.xtext.example.graphemodele » sous « src-gen » le package ci-dessous est généré:


3. Projet « ... graphemodel.ui »

Ce projet défini l'interface utilisateur.

On crée un « package » pour recevoir notre code (Handler)

Nommer le « package » :

Cliquer « Finish ».

Le « package » est créé :


3-1. Commande View Model

Une commande « View Model » est ajoutée pour visualiser le modèle édité. Ouvrir le « Plugin Manifest Editor » sélectionner l'onglet « Extension », initialement nous avons :

On édite le fichier « plugin.xml » pour ajouter une commande:

     <extension
         point="org.eclipse.ui.commands">
      <command
            id="viewModel"
            name="View Model">
      </command>
   </extension>
   <extension
         point="org.eclipse.ui.handlers">
      <handler
            class="monCode.ViewModelHandler"
            commandId="viewModel">
      </handler>
   </extension>
   <extension
         point="org.eclipse.ui.menus">
      <menuContribution
            allPopups="false"
            locationURI="menu:org.eclipse.ui.main.menu?after=additions">
         <command
               commandId="viewModel"
               style="push">
         </command>
      </menuContribution>
   </extension>
Revenons à l'onglet « Extensions » on a ajouté :


3-2. Définition du « Handler »

On sélectionne (handler) dans « Extension Element Details » cliquer « class: »

« New Java Class – Java Class » est initialisé:

Cliquer « Finish » on obtient:

ce qui correspond au code:

package monCode;

import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.commands.IHandlerListener;

public class ViewModelHandler implements IHandler {

	@Override
	public void addHandlerListener(IHandlerListener handlerListener) {
		// TODO Auto-generated method stub
	}

	@Override
	public void dispose() {
		// TODO Auto-generated method stub
	}

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean isEnabled() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isHandled() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void removeHandlerListener(IHandlerListener handlerListener) {
		// TODO Auto-generated method stub
	}
}
On édite le handler:

package monCode;

import java.util.ListIterator;

import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.commands.IHandlerListener;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.xtext.example.GraphemodelStandaloneSetup;
import org.eclipse.xtext.example.graphemodel.Arc;
import org.eclipse.xtext.example.graphemodel.Graphe;
import org.eclipse.xtext.example.graphemodel.GrapheElement;

public class ViewModelHandler implements IHandler {

	@Override
	public void addHandlerListener(IHandlerListener handlerListener) {
	}

	@Override
	public void dispose() {
	}

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {
		Shell shell = HandlerUtil.getActiveShell(event);
		
		ISelection selection = HandlerUtil.getCurrentSelection(event);
		String nomFich = selection.toString();
		nomFich = nomFich.substring(2, nomFich.length()-1);
		//MessageDialog.openInformation(shell, "Working with EMF Models", nomFich);	
		
		
		new GraphemodelStandaloneSetup().createInjectorAndDoEMFRegistration();
		ResourceSet rs = new ResourceSetImpl();
		
		Resource resource;
		try {
			resource = rs.getResource(URI.createURI("platform:/resource/"+nomFich),true);
			// autre possibilité:
			//resource = rs.getResource(URI.
			//				createPlatformResourceURI(nomFich,true), true);
		} catch (Exception e) {
			// e.printStackTrace();
			MessageDialog.openError( shell, "Working with EMF Models", "Select a file in Project Explorer");
			return null;
		}
		
		StringBuffer message = new StringBuffer("Modèle: "+ nomFich + "\n");
		EObject eobject = resource.getContents().get(0);
		Graphe graphe = (Graphe) eobject;
		EList<GrapheElement> grapheElementList = graphe.getGrapheElements();
		ListIterator<GrapheElement> li = grapheElementList.listIterator();
		while (li.hasNext()){
			GrapheElement grapheElement = li.next();
			if (grapheElement instanceof Arc){
				Arc arc = (Arc)grapheElement;
				message.append(arc.getName()
						+ "("
						+ arc.getOrigine().getReference().getName()
						+ " -> "
						+ arc.getExtremite().getReference().getName()
						+ ")\n"				
				);
			}
		}
		MessageDialog.openInformation(shell, "Working with EMF Models", message.toString());
		
		return null;
	}

	@Override
	public boolean isEnabled() {
		return true;
	}

	@Override
	public boolean isHandled() {
		return true;
	}

	@Override
	public void removeHandlerListener(IHandlerListener handlerListener) {
	}
}
Faire une sauvegarde générale.


4. Test

Faire un clic droit sur le projet « org.xtext.exemple.graphemodel.ui » dans le menu contextuel sélectionner la commande «  Run As > Run Configurations... ». Dans « Run Configuration » double cliquer « Eclipse Application ». Nommer la configuration « DSL_Graphe ». Faire « Apply » puis « Run »

Sous la nouvelle plate-forme, on crée un simple projet de type « General > Project » de nom « testEditionGraphe ». Sous ce projet on crée un fichier « graphe1.graphe » le postfixe « graphe » induit le choix de l'éditeur.


4-1. L'éditeur

L'éditeur est un éditeur syntaxique coloré.

Le source définissant une instance de graphe :

// Les noeuds
Noeud { nom start }
Noeud { nom n1 }
Noeud { nom n2 }
Noeud { nom end }
// Les arcs
Arc { nom arc1 origine start extremite n1 }
Arc { nom arc2 origine start extremite n2 }
Arc { nom arc3 origine n1 extremite end }
Arc { nom arc4 origine n2 extremite end }
Arc { nom arc5 origine end extremite start }
Faire une sauvegarde après l'édition.


4-2. La commande « View Model »

Dans le « Project Explorer » sélectionner « graphe1.graphe ». La commande « View Model » accède à la représentation du modèle édité et en donne une représentation textuelle:


5. Une autre grammaire

On peut définir une autre grammaire:

grammar org.eclipse.xtext.example.Graphemodel with org.eclipse.xtext.common.Terminals

generate graphemodel "http://www.eclipse.org/xtext/example/Graphemodel"

Graphe:
   {Graphe}
   'Graphe'
   '{'
      ( grapheElements += GrapheElement(',' grapheElements += GrapheElement)* )?
   '}'
   ;
   
GrapheElement:
   Noeud | Arc ;

Arc:
	'Arc'
	'{'
		'nom' name=ID
		':'  origine= NoeudOrigine
		'->' extremite= NoeudExtremite
    '}';

NoeudOrigine:
   reference=[Noeud];
   
NoeudExtremite:
   reference=[Noeud];
   
Noeud:
	'Noeud'
	'{'
		'nom' name=ID
    '}';
ce qui donne la syntaxe ci-dessous:

La commande « View Model » reste valide.


6. Conclusion

A partir d'une grammaire nous avons généré un éditeur syntaxique coloré. Nous avons utilisé Java pour accéder au modèle généré. D'autres solutions sont possibles en particulier pour écrire des générateurs de code à partir du langage spécialisé « M2T Xpand ».

Pour plus de précision voir:



               Version PDF (Miroir)   Version hors-ligne (Miroir)

Valid XHTML 1.0 TransitionalValid CSS!

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2011 . Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Responsables bénévoles de la rubrique Eclipse : Mickael Baron - Robin56 -