|
|
Rappels :
Vous devez fournir des copies d'écran des diagrammes de classe de BlueJ,
et la documentation générée doit faire apparaître
vos commentaires sur toutes les classes, les méthodes, les paramètres,
et les valeurs de retour.
Question 1. (Évaluation d'expression)
(i) Selon le Pattern Composite, la grammaire d'une expression arithmétique peut être décrite par cette hiérarchie de classes :
AIDE :
|
(ii) Il s'agit maintenant de pouvoir évaluer des expressions.
Pour cela, le pattern Interpréteur propose de définir
à l'intérieur de la classe Expression et de ses sous-classes
une méthode interprete() qui se sert d'une pile pour évaluer
chaque morceau d'expression.
Si on reprend la pile de la question 2 du TP3, la signature de cette méthode
est :
public void interprete( PileI p ) throws Exception
La hiérarchie de classes devient donc
(hors classes d'exception de la pile) :
*** (iii) Mettez en commun dans la classe OpBinaire les instructions communes à Addition et à Multiplication, puis ajoutez suivant le même modèle les opérations de Soustraction et de Division.
Cette question est optionnelle. Si vous ne la traitez pas, n'utilisez que des additions et des multiplications dans la suite.
L'expression à construire et à évaluer est maintenant :
10/5 - 2*4 + 1
Ça fait bien -5 ?
Vous avez donc bien respecté l'associativité à gauche de Java.
(iv) Fournir une classe de test unitaire pour Nombre, et Addition et/ou Multiplication.
*** (v) Fournir une classe de test global, dans le style de TestExpression, pour vérifier le bon fonctionnement de l'ensemble (menu New Class puis Unit Test).
(vi) Fournissez la documentation regroupant toutes les classes des questions (i) (ii) (iv) et éventuellement (iii) et (v).
Question 2. (Parsing)
(i) L'analyse syntaxique d'une expression arithmétique est réalisée par la classe ArithmeticExpression (Attention! cette classe utilise l'associativité à droite, mais cela nous évite d'avoir à redévelopper une telle classe).
Elle respecte la grammaire traditionnelle des expressions entières suivante, en formalisme apparenté BNF/DCG:
parseE --> parseT parseE --> parseT , [+] , parseE. parseE --> parseT , [-] , parseE. parseT --> parseF. parseT --> parseF , [*] , parseT. parseT --> parseF , [/] , parseT. parseF --> ['('] , parseE , [')']. parseF --> [N] , {integer(N)}.En utilisant cette classe dans le programme de la question 1.iii, proposez une série de tests variés.
(ii) Proposez une applette de test permettant de rentrer une expression arithmétique telle que 10/5-(2*4+1) et de l'évaluer.
Un exemple de ce que cela peut donner : Attention ! ne pas mettre d'espaces dans l'expression |
|
AIDE :
|
(iii) Fournissez la documentation regroupant toutes les classes des questions (i) et (ii).
Question 3. (Sérialisation)
(i) Ajoutez les méthodes de classe pour sauvegarder et restituer une Expression.
Avant toute chose, il est conseillé de lire le premier des quatre chapitres du document sur la sérialisation cité dans le cadre au début de ce sujet.
Leurs signatures devraient être :
public static void sauvegarder( Expression exp, String nomfichier ) throws Exception public static Expression restituer( String nomfichier ) throws Exception
Pour pouvoir être sérialisée, une classe doit implémenter l'interface Serializable.
AIDE :
|
(ii) Ajoutez à la fin du main() de TestExpression de la question 2.i un test de sérialisation.
Ce test comprendra la sauvegarde de l'expression, l'instruction exp = null; pour détruire l'objet, puis la restitution de l'expression et son évaluation pour vérifier que le résultat est toujours le même.
*** (iii) Modifiez l'IHM de la question 2.ii pour pouvoir tester interactivement la sérialisation.
Cette question est optionnelle.
Pour cela, ajoutez une deuxième "ligne" comprenant un champ de saisie pour le nom de fichier (Expression.ser par défaut), et deux boutons sauvegarder et restituer.
Un exemple de ce que cela peut donner : Attention ! ne pas mettre d'espaces dans l'expression |
|
ATTENTION !
|
(iv) Fournissez la documentation regroupant toutes les classes des questions (i) (ii) (iii).
OPTIONNEL* :Question 4. (toString) (i) Redéfinissez toString() dans les 4 opérations et dans Nombre. (ii) Ajoutez dans l'applette de la question 3.iii l'affichage dans le champ de saisie de l'expression restituée. |
Annexe 1. Source de ArithmeticExpression.java
// tp6-2i : ArithmeticExpression.java import java.util.StringTokenizer; /** Analyseur syntaxique. Attention ! * la grammaire des expressions associativité à droite ! * parseE --> parseT. * parseE --> parseT , [+] , parseE. * parseE --> parseT , [-] , parseE. * * parseT --> parseF. * parseT --> parseF , [*] , parseT. * parseT --> parseF , [/] , parseT. * * parseF --> [(] , parseE , [)]. * parseF --> [N] {integer(N)}. * * @see StringTokenizer */ public class ArithmeticExpression { /** en entrée l'expression infixée. */ private String infix; /** l'analyseur lexical. */ private StringTokenizer str; /** le prochain caractère du flot en entrée. */ private String next; /** Création d'une instance. * * @param s l'expression infixée selon la grammaire. */ public ArithmeticExpression( String s ) { infix = s + "$"; str = new StringTokenizer( infix, "()+-*/$", true ); } // ArithmeticExpression() /** la version infixée de l'expression */ public String toString() { return infix; } /** Analyse syntaxique. * * @return Une instance de la classe expression */ public Expression parse() { next = str.nextToken(); return parseE(); } // parse() /** Analyse syntaxique: parseE. * * @return Une instance de la classe Expression */ private Expression parseE( ) { // parse an Expression String op; Expression exp1 = parseT(); if ( next.equals( "+" ) || next.equals( "-" ) ) { op = next; next = str.nextToken(); Expression exp2 = parseE(); if( op.equals( "+" ) ) return new Addition( exp1, exp2 ); else // op.equals( "-" ) return new Soustraction( exp1, exp2 ); } return exp1; } // parseE() /** Analyse syntaxique: parseT. * * @return Une instance de la classe Expression */ private Expression parseT() { // parse a Term String op; Expression exp1 = parseF(); if ( next.equals( "*" ) || next.equals( "/" ) ) { op = next; next = str.nextToken(); Expression exp2 = parseT(); if( op.equals( "*" ) ) return new Multiplication( exp1, exp2 ); else // op.equals( "/" ) return new Division( exp1, exp2 ); } return exp1; } // parseT() /** Analyse syntaxique: parseF. * * @return Une instance de la classe Expression */ private Expression parseF() { // parse a Factor Expression exp; if ( next.equals( "(" ) ) { next = str.nextToken(); exp = parseE(); next = str.nextToken(); return exp; } else { exp = new Nombre( Integer.parseInt( next ) ); next = str.nextToken(); return exp; } } // parseF() } // ArithmeticExpression
Annexe 2. Source de AppletteTPExpression.java
// tp6-2ii : AppletteTPExpression.java import java.applet.Applet; /** * L'applette. */ public class AppletteTPExpression extends Applet { private IHMExpression ihmExpression; public void init() { ihmExpression = new IHMExpression(); add( ihmExpression ); } // init() } // AppletteTpExpression
Annexe 3. Source de IHMExpression.java
// tp6-2ii : IHMExpression.java import java.awt.*; import java.awt.event.*; public class IHMExpression extends Panel implements ActionListener { private TextField saisie = new TextField( 20 ); private Button boutonEvaluer = new Button( "évaluer" ); private TextField resultat = new TextField( 4 ); private Expression exp; private PileI p = new Pile( 20 ); public IHMExpression() { setLayout( new BorderLayout() ); Panel pa = new Panel(); pa.add( saisie ); saisie.setText( "3+2*4" ); pa.add( boutonEvaluer ); resultat.setEnabled( false ); pa.add( resultat ); add( pa, "North" ); boutonEvaluer.addActionListener( this ); saisie.addActionListener( this ); } // IHMExpression() public void actionPerformed( ActionEvent ae ) { try { // à compléter } catch( Exception e ) { resultat.setText( "0000" ); e.printStackTrace(); } // catch() } // actionPerformed() } // IHMExpression
Annexe 4. Source de Person.java
// Person.java import java.io.*; public class Person implements Serializable { private String firstName; private String lastName; private String password; // transient Thread worker; public Person( String firstName, String lastName, String password ) { this.firstName = firstName; this.lastName = lastName; this.password = password; } // Person() public String toString() { return new String( lastName + " " + firstName + " : " + password ); } // utile uniquement car on veut coder le mot de passe private void writeObject( ObjectOutputStream oos ) throws IOException { password = code( password ); // code oos.defaultWriteObject(); password = code( password ); // décode } // writeObject() // utile uniquement car on veut décoder le mot de passe private void readObject( ObjectInputStream ois ) throws IOException, ClassNotFoundException { ois.defaultReadObject(); password = code( password ); // décode } // readObject() private String code( String s ) { // ceci n'est pas un cryptage sérieux ! String r = new String( "" ); for ( int i=s.length()-1; i>=0; i-- ) r += s.charAt( i ); return r; } // code() } // Person
Annexe 5. Source de WritePerson.java
// WritePerson.java import java.io.*; public class WritePerson { public static void main( String [] args ) { Person p = new Person( "Fred", "Wesley", "cantguessthis" ); ObjectOutputStream oos = null; try { oos = new ObjectOutputStream( new FileOutputStream( "Person.ser" ) ); oos.writeObject( p ); } catch ( Exception e ) { e.printStackTrace(); } finally { if ( oos != null ) { try { oos.flush(); } catch ( IOException ioe ) { System.out.println( "can't flush !" ); } try { oos.close(); } catch ( IOException ioe ) { System.out.println( "can't close !" ); } } // if } // finally } // main() } // WritePerson
Annexe 6. Source de ReadPerson.java
// ReadPerson.java import java.io.*; public class ReadPerson { public static void main( String [] args ) { ObjectInputStream ois = null; try { ois = new ObjectInputStream( new FileInputStream( "Person.ser" ) ); Object o = ois.readObject(); System.out.println( "Read object " + o ); } catch ( Exception e ) { e.printStackTrace(); } finally { if ( ois != null ) { try { ois.close(); } catch ( IOException ioe ) { System.out.println( "can't close !" ); } } // if } // finally } // main() } // ReadPerson