Codes sources prototype 1

This commit is contained in:
SylvanCourtiol
2021-05-09 17:42:30 +02:00
parent 14d39af284
commit a1161d0399
16 changed files with 1144 additions and 73 deletions
+165
View File
@@ -0,0 +1,165 @@
/**
* Analyseur.java 9 mai 2021
* IUT Rodez info1 2020-2021, pas de copyright, aucun droit
*/
package interpreteurlir;
import java.lang.reflect.InvocationTargetException;
import java.util.Scanner;
import interpreteurlir.expressions.Expression;
import interpreteurlir.motscles.Commande;
/**
* Analyseur de l'entrée standard du programme interpréteur LIR.
* @author Nicolas Caminade
* @author Sylvan Courtiol
* @author Pierre Debas
* @author Heïa Dexter
* @author Lucas Vabre
*/
public class Analyseur {
/** Symbole d'invite de commande */
public static final String INVITE = "? ";
/** Message feedback ok */
public static final String OK_FEEDBACK = "ok";
/** Message feedback not ok */
public static final String NOK_FEEDBACK = "nok : ";
/** analyseur de l'entrée standard */
private Scanner entree;
/** contexte de cet analyseur */
private Contexte contexteGlobal;
/**
* Initialise un analyseur ayant son propre contexte.
*/
public Analyseur() {
super();
entree = new Scanner(System.in);
contexteGlobal = new Contexte();
Expression.referencerContexte(contexteGlobal);
}
/**
* Lance la boucle qui demande puis exécute des commandes ou instructions
* saisies par l'utilisateur.
*/
public void mainLoop() {
String ligneSaisie;
for (;;) {
System.out.print(INVITE);
ligneSaisie = entree.nextLine().trim();
String[] decoupage = ligneSaisie.split(" ", 2);
String motCle = decoupage.length >= 1 ? decoupage[0] : "";
String arguments = decoupage.length >= 2 ? decoupage[1] : "";
executerCommande(motCle, arguments.trim());
}
}
/**
* Recherche la commande et exécute cette commande si présente.
* Affiche un feedback si la commande ne s'en occupe pas ou erreur.
* @param motCle chaîne contenant le mot clé de la commande/instruction
* @param arguments reste de la ligne saisie après le mot clé
*/
private void executerCommande(String motCle, String arguments) {
Class<?> aExecuter;
/* recherche de la class */
try {
aExecuter = rechercheCommande(motCle);
Class<?> classeArg = String.class;
Class<?> classeContexte = Contexte.class;
Commande cmd = (Commande)aExecuter
.getConstructor(classeArg, classeContexte)
.newInstance(arguments, contexteGlobal);
feedback(cmd.executer());
} catch ( InvocationTargetException | IllegalAccessException
| InstantiationException | NoSuchMethodException
| InterpreteurException lancee) {
System.err.println(NOK_FEEDBACK
+ (lancee.getMessage() != null
? lancee.getMessage()
: lancee.getCause().getMessage()));
}
}
/**
* Affiche feedback de bon déroulement
* d'une commande si celle ci n'affiche rien.
* @param afficheRien true si feedback déjà fait par la commande sinon false
*/
private static void feedback(boolean afficheRien) {
if (!afficheRien) {
System.out.println(OK_FEEDBACK);
}
}
/**
* Recherche la commande ou instruction correspondant au mot clé.
* <ul><li>Les commandes doivent être
* dans le package interpreteurlir.motscles</li>
* <li>Les instructions doivent être
* dans le package interpreteurlir.motscles.instructions</li>
* <ul>
* La classe correspondant doit avoir un nom qui se finit avec le mot clé
* (première lettre en majuscule)
* @param motCle mot clé de la commande/ instruction
* @return Classe de cette commande.
* @throws InterpreteurException si motCle est vide, null ou non reconnue
*/
private static Class<?> rechercheCommande(String motCle) {
final String ERREUR_VIDE = "ligne vide";
final String ERREUR_INCONNU = "mot clé inconnu";
final String CLASS_PATH_CMD = "interpreteurlir.motscles.Commande";
final String CLASS_PATH_INST =
"interpreteurlir.motscles.instructions.Instruction";
if (motCle == null || motCle.isBlank()) {
throw new InterpreteurException(ERREUR_VIDE);
}
motCle = (Character.toUpperCase(motCle.charAt(0)))
+ (motCle.length() > 1 ? motCle.substring(1) : "");
Class<?> aChercher;
try {
aChercher = Class.forName(CLASS_PATH_CMD + motCle);
} catch(ClassNotFoundException nonCmd) {
try {
aChercher = Class.forName(CLASS_PATH_INST + motCle);
} catch(ClassNotFoundException nonInst) {
throw new InterpreteurException(ERREUR_INCONNU);
}
}
return aChercher;
}
/**
* Lancement de l'interpréteur LIR.
* Un analyseur est créé.
* @param args non utilisé
*/
public static void main(String[] args) {
final String MESSAGE_LANCEMENT =
"Interpréteur Langage IUT de Rodez, bienvenue !\n"
+ "Entrez vos commandes et instructions après linvite "
+ INVITE + "\n";
System.out.println(MESSAGE_LANCEMENT);
new Analyseur().mainLoop();
}
}
@@ -6,6 +6,8 @@
package interpreteurlir.donnees; package interpreteurlir.donnees;
import interpreteurlir.InterpreteurException;
/** /**
* @author Nicolas Caminade * @author Nicolas Caminade
* @author Sylvan Courtiol * @author Sylvan Courtiol
@@ -29,7 +31,7 @@ implements Comparable<Identificateur> {
public Identificateur(String identificateur) { public Identificateur(String identificateur) {
super(); super();
if(!isIdentificateur(identificateur)) { if(!isIdentificateur(identificateur)) {
throw new IllegalArgumentException(identificateur throw new InterpreteurException(identificateur
+ " n'est pas un identificateur"); + " n'est pas un identificateur");
} }
@@ -6,6 +6,8 @@
package interpreteurlir.donnees; package interpreteurlir.donnees;
import interpreteurlir.InterpreteurException;
/** /**
* Identificateur de chaîne * Identificateur de chaîne
* @author Nicolas Caminade * @author Nicolas Caminade
@@ -19,13 +21,14 @@ public class IdentificateurChaine extends Identificateur {
/** /**
* Instantiation d'identificateur de chaîne * Instantiation d'identificateur de chaîne
* @param identificateur a instancier * @param identificateur a instancier
* @throws IllegalAccessException si l'identificateur est invalide * @throws InterpreteurException si l'identificateur est invalide
*/ */
public IdentificateurChaine(String identificateur) { public IdentificateurChaine(String identificateur) {
super(identificateur); super(identificateur.trim());
identificateur = identificateur.trim();
if(!isIdentificateurChaine(identificateur)) { if(!isIdentificateurChaine(identificateur)) {
throw new IllegalArgumentException(identificateur throw new InterpreteurException(identificateur
+ " n'est pas un identificateur" + " n'est pas un identificateur"
+ " de chaine"); + " de chaine");
} }
@@ -6,6 +6,8 @@
package interpreteurlir.donnees; package interpreteurlir.donnees;
import interpreteurlir.InterpreteurException;
/** /**
* Identificateur d'entier * Identificateur d'entier
* @author Nicolas Caminade * @author Nicolas Caminade
@@ -19,15 +21,15 @@ public class IdentificateurEntier extends Identificateur {
/** /**
* Instantiation d'identificateur d'entier * Instantiation d'identificateur d'entier
* @param identificateur a instancier * @param identificateur a instancier
* @throws IllegalAccessException si l'identificateur est invalide * @throws InterpreteurException si l'identificateur est invalide
*/ */
public IdentificateurEntier(String identificateur) { public IdentificateurEntier(String identificateur) {
super(identificateur); super(identificateur);
if(!isIdentificateurEntier(identificateur)) { if(!isIdentificateurEntier(identificateur)) {
throw new IllegalArgumentException(identificateur throw new InterpreteurException(identificateur
+ " n'est pas un identificateur" + " n'est pas un identificateur"
+ " d'entier"); + " d'entier");
} }
} }
+54 -41
View File
@@ -1,80 +1,93 @@
/** /**
* Variable.java 8 mai 2021 * Variable.java 8 mai 2021
* IUT Rodez info1 2020-2021, pas de copyright, aucun droit * IUT-Rodez info1 2020-2021, pas de droits, pas de copyrights
*/ */
package interpreteurlir.donnees; package interpreteurlir.donnees;
import interpreteurlir.donnees.litteraux.Chaine;
import interpreteurlir.donnees.litteraux.Litteral; import interpreteurlir.donnees.litteraux.Litteral;
import interpreteurlir.InterpreteurException;
/** TODO commenter la responsabilité de cette classe /**
* BOUCHON * Associe un littéral à un identificateur
*
* @author Nicolas Caminade * @author Nicolas Caminade
* @author Sylvan Courtiol * @author Sylvan Courtiol
* @author Pierre Debas * @author Pierre Debas
* @author Heïa Dexter * @author Heia Dexter
* @author Lucas Vabre * @author Lucas Vabre
*
*/ */
public class Variable implements Comparable<Variable> { public class Variable extends Object implements Comparable<Variable> {
/** BOUCHON identificateurs car Identificateurs non finis */ /** Identificateur de cette variable */
private Identificateur identificateur; private Identificateur identificateur;
/** BOUCHON valeur*/ /** Valeur de cette variable */
private Litteral valeur; private Litteral valeur;
/** TODO commenter l'état initial
* @param id /**
* @param valeur * Initialise une variable
* @param identificateur associé à cette variable
* @param valeur associé à cette variable
* @throws InterpreteurException en cas d'incompatibilité entre
* l'identificateur et le type de la valeur à lui associer
*/ */
public Variable(Identificateur id, Litteral valeur) { public Variable(Identificateur identificateur, Litteral valeur) {
super(); if (!isVariable(identificateur, valeur)) {
this.identificateur = id; throw new InterpreteurException("Identificateur '"
+ identificateur.toString()
+ "' et type de "
+ valeur.toString()
+ "incompatible.");
}
this.identificateur = identificateur;
this.valeur = valeur; this.valeur = valeur;
} }
private static boolean isVariable(Identificateur id, Litteral valeur) {
return id instanceof IdentificateurChaine && valeur instanceof Chaine
/* || id instanceof IdentificateurEntier && valeur instanceof Entier */;
}
/** /**
* @return valeur de valeur * @return la valeur de cette variable
*/ */
public Litteral getValeur() { public Litteral getValeur() {
return valeur; return valeur;
} }
/** /**
* @param valeur nouvelle valeur de valeur * Modifie la valeur de cette variable
* @param nouvelleValeur
*/ */
public void setValeur(Litteral valeur) { public void setValeur(Litteral nouvelleValeur) {
this.valeur = valeur; if (isVariable(identificateur, nouvelleValeur)) {
} this.valeur = nouvelleValeur;
}
/* non javadoc
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo(Variable o) {
// bouchon
return identificateur.compareTo(o.identificateur);
} }
/** /**
* @return valeur de id * @return l'identificateur de cette variable
*/ */
public Identificateur getIdentificateur() { public Identificateur getIdentificateur() {
return identificateur; return identificateur;
} }
/* non javadoc /* non javadoc @see java.lang.Object#toString() */
* @see java.lang.Object#toString()
*/
@Override @Override
public String toString() { public String toString() {
return identificateur + " = " + valeur; return identificateur.toString() + " = " + valeur.toString();
}
public int compareTo(Variable aComparer) {
return identificateur.compareTo(aComparer.identificateur);
} }
}
}
@@ -38,7 +38,7 @@ public class Chaine extends Litteral {
* @param uneValeur * @param uneValeur
*/ */
public Chaine(String uneValeur) { public Chaine(String uneValeur) {
uneValeur = uneValeur.trim();
if (!uneValeur.startsWith("\"") || !uneValeur.endsWith("\"")) { if (!uneValeur.startsWith("\"") || !uneValeur.endsWith("\"")) {
throw new InterpreteurException(ERREUR_INVALIDE throw new InterpreteurException(ERREUR_INVALIDE
+ uneValeur); + uneValeur);
@@ -61,7 +61,7 @@ public class Chaine extends Litteral {
*/ */
public static Chaine concatener(Chaine a, Chaine b) { public static Chaine concatener(Chaine a, Chaine b) {
return null; return new Chaine("\"" + a.valeur + b.valeur + "\"");
} }
/* non javadoc /* non javadoc
@@ -7,6 +7,8 @@ package interpreteurlir.donnees.litteraux.tests;
import interpreteurlir.InterpreteurException; import interpreteurlir.InterpreteurException;
import interpreteurlir.donnees.litteraux.Chaine; import interpreteurlir.donnees.litteraux.Chaine;
import static info1.outils.glg.Assertions.*;
/** /**
* Tests unitaires de Chaine * Tests unitaires de Chaine
* @author Nicolas Caminade * @author Nicolas Caminade
@@ -111,6 +113,32 @@ public class TestChaine {
System.out.println("==>test terminé\n"); System.out.println("==>test terminé\n");
} }
/**
* Tests unitaires de concaténer
*/
public void testConcatener() {
final Chaine[] ATTENDU = {
new Chaine(),
new Chaine("\"Bonjour le monde ! \""),
new Chaine("\" \""),
new Chaine("\"3,1415\""),
};
final Chaine[][] A_CONCATENER = {
{new Chaine(), new Chaine("\"\"")},
{new Chaine("\"Bonjour \""), new Chaine("\"le monde ! \"")},
{new Chaine("\"\""), new Chaine("\" \"")},
{new Chaine("\"3,\""), new Chaine("\"1415\"")},
};
System.out.println("\tExécution du test de concaténer");
for (int numTest = 0 ; numTest < ATTENDU.length ; numTest++ ) {
assertTrue(ATTENDU[numTest].compareTo(Chaine.concatener(
A_CONCATENER[numTest][0], A_CONCATENER[numTest][1]))
== 0);
}
}
/** /**
* Lancement des tests * Lancement des tests
* @param args non utilisés * @param args non utilisés
@@ -0,0 +1,210 @@
/**
* TestVariable.java 8 mai 2021
* IUT-Rodez info1 2020-2021, pas de droits, pas de copyrights
*/
package interpreteurlir.donnees.tests;
import interpreteurlir.donnees.Variable;
import interpreteurlir.donnees.IdentificateurChaine;
import interpreteurlir.donnees.IdentificateurEntier;
import interpreteurlir.donnees.litteraux.*;
import interpreteurlir.InterpreteurException;
import static info1.outils.glg.Assertions.*;
/**
* Tests unitaires de la classe Variable
*
* @author Nicolas Caminade
* @author Sylvan Courtiol
* @author Pierre Debas
* @author Heia Dexter
* @author Lucàs Vabre
*/
public class TestVariable {
/** Jeu d'identificateurs de chaîne valides */
private static final IdentificateurChaine[] ID_CHAINE = {
new IdentificateurChaine("$a"),
new IdentificateurChaine("$B"),
new IdentificateurChaine("$alpha"),
new IdentificateurChaine("$Alpha"),
new IdentificateurChaine("$Alpha5"),
new IdentificateurChaine("$jeSuisUnTresLongIdentifi"),
new IdentificateurChaine("$R2D2"),
new IdentificateurChaine("$MichelSardou"),
new IdentificateurChaine("$PhilippePoutou2022")
};
/** Jeu d'identificateurs d'entier valides */
private static final IdentificateurEntier[] ID_ENTIER = {
new IdentificateurEntier("a"),
new IdentificateurEntier("A"),
new IdentificateurEntier("alpha"),
new IdentificateurEntier("Alpha"),
new IdentificateurEntier("Alpha5"),
new IdentificateurEntier("jeSuisUnTresLongIdentifi"),
new IdentificateurEntier("R2D2"),
new IdentificateurEntier("MichelSardou"),
new IdentificateurEntier("PhilippePoutou2022")
};
/** Jeu de chaînes valides */
private static final Chaine[] VALEURS_CHAINE = {
new Chaine(),
new Chaine("\"arztyehjklmpoijhghnbghjklmpoiuytrf"
+ "ghjnklmpoiuytrezaqsdfghnjklmpjbfrtyu\""),
new Chaine("\"\""),
new Chaine("\"coucou \""),
new Chaine("\"" + Integer.toString(42) + "\""),
new Chaine("\"Bidon\""),
new Chaine("\"toto\""),
new Chaine("\"tata\t\""),
new Chaine("\"titi\n\"")
};
// /** Jeu d'entiers valides */
// private static final Entier[] VALEUR_ENTIER = {
// // TODO: jeu d'entiers valide
// };
/** Jeu de variables chaîne valides*/
private static Variable[] fixtureChaine = new Variable[ID_CHAINE.length];
/* Jeu de variables entières valides*/
//private static Variable[] fixtureEntier= new Variable[ID_ENTIER.length];
private static void fixtureReload() {
for (int i = 0; i < ID_CHAINE.length; i++) {
fixtureChaine[i] = new Variable(ID_CHAINE[i], VALEURS_CHAINE[i]);
}
//TODO reload fixtureEntier
}
/**
* Test unitaire du constructeur Variable(Identificateur, Littéral)
*/
public static void testVariableIdentificateurChaineLitteral() {
for (int noJeu = 0; noJeu < VALEURS_CHAINE.length; noJeu++) {
try {
//new Variable(ID_CHAINE[noJeu], VALEURS_CHAINE[noJeu]); // bouchon
new Variable(ID_ENTIER[noJeu], VALEURS_CHAINE[noJeu]);
// TODO tester avec la classe Entier
// new Variable(ID_CHAINE[noJeu], VALEURS_ENTIER[noJeu]);
echec();
} catch (InterpreteurException lancee) {
// test OK
}
}
}
/**
* Test unitaire de getIdentificateur() d'une variable chaîne
*/
public static void testGetIdentificateurChaine() {
fixtureReload();
for (int i = 0; i < VALEURS_CHAINE.length; i++ ) {
assertTrue(ID_CHAINE[i].compareTo(fixtureChaine[i]
.getIdentificateur()) == 0);
}
}
/**
* Test unitaire de getIdentificateur() d'une variable entière
*/
public static void testGetIdentificateurEntier() {
// fixtureReload();
//
// for (int i = 0; i < VALEURS_Entier.length; i++ ) {
// assertTrue(ID_ENTIER[i].compareTo(fixtureEntier[i]
// .getIdentificateur()) == 0);
// }
echec();
}
/**
* Test unitaire de getValeur() d'une variable chaîne
*/
public static void testGetValeurChaine() {
fixtureReload();
for (int i = 0; i < VALEURS_CHAINE.length; i++ ) {
assertTrue(VALEURS_CHAINE[i]
.compareTo(fixtureChaine[i].getValeur()) == 0);
}
}
/**
* Test unitaire de setValeur() d'une chaîne
*/
public static void testSetValeurChaine() {
fixtureReload();
final Chaine[] NOUVELLE_CHAINE = {
new Chaine("\"titi\""),
new Chaine("\"Mathématiques\""),
new Chaine("\"!?9563Message\""),
new Chaine("\"test TESTS\""),
new Chaine("\"-5 + 962\"")
};
for (int i = 0; i < NOUVELLE_CHAINE.length; i++) {
fixtureChaine[i].setValeur(NOUVELLE_CHAINE[i]);
assertTrue(NOUVELLE_CHAINE[i]
.compareTo(fixtureChaine[i].getValeur()) == 0);
}
}
/**
* Test unitaire de toString()
*/
public static void testToString() {
fixtureReload();
final String[] ATTENDUS = {
"$a = \"\"",
"$B = \"arztyehjklmpoijhghnbghjklmpoiuytrf"
+ "ghjnklmpoiuytrezaqsdfghnjklmpjbfrtyu\"",
"$alpha = \"\"",
"$Alpha = \"coucou \"",
"$Alpha5 = \"42\"",
"$jeSuisUnTresLongIdentifi = \"Bidon\"",
"$R2D2 = \"toto\"",
"$MichelSardou = \"tata\t\"",
"$PhilippePoutou2022 = \"titi\n\""
};
for (int noJeu = 0; noJeu < fixtureChaine.length; noJeu++ ) {
assertEquivalence(fixtureChaine[noJeu].toString(),
ATTENDUS[noJeu]);
}
}
/**
* Test unitaire de compareTo()
*/
public static void testCompareTo() {
fixtureReload();
final Variable REF_MIN
= new Variable(new IdentificateurChaine("$A"),
new Chaine("\"Min\""));
final Variable REF_MAX
= new Variable(new IdentificateurChaine("$z"),
new Chaine("\"Max\""));
for(int noJeu = 0; noJeu < fixtureChaine.length; noJeu++) {
assertTrue(fixtureChaine[noJeu].compareTo(REF_MIN) > 0);
assertTrue(fixtureChaine[noJeu].compareTo(REF_MAX) < 0);
assertTrue(fixtureChaine[noJeu].compareTo(fixtureChaine[noJeu]) == 0);
}
// TODO Faire le même test pour les variables contenant des entiers
}
}
@@ -6,6 +6,7 @@ package interpreteurlir.expressions;
import interpreteurlir.Contexte; import interpreteurlir.Contexte;
import interpreteurlir.InterpreteurException; import interpreteurlir.InterpreteurException;
import interpreteurlir.donnees.Identificateur;
import interpreteurlir.donnees.litteraux.Litteral; import interpreteurlir.donnees.litteraux.Litteral;
/** /**
@@ -19,11 +20,24 @@ import interpreteurlir.donnees.litteraux.Litteral;
* @author Lucas Vabre * @author Lucas Vabre
*/ */
public class Expression { public class Expression {
/** Index de l'operande gauche */
protected static final int INDEX_OPERANDE_G = 0;
/** Index de l'operande droite */
protected static final int INDEX_OPERANDE_D = 1;
/** Index de de l'identificateur pour l'affectation */
protected static final int INDEX_AFFECTATION = 2;
/** Contexte global pour accéder aux données. */ /** Contexte global pour accéder aux données. */
private static Contexte contexteGlobal; protected static Contexte contexteGlobal;
// TODO stocker opérandes (identificateur ou Litteral) /** Identificateurs opérandes de cette l'expression */
protected Identificateur[] identificateursOperandes;
/** Littéraux opérandes de cette expression */
protected Litteral[] litterauxOperandes;
/** /**
* Initialise une expression par défaut avec les liens nécessaires à * Initialise une expression par défaut avec les liens nécessaires à
@@ -31,16 +45,26 @@ public class Expression {
*/ */
protected Expression() { protected Expression() {
super(); super();
final int NB_IDENTIFICATEUR = 3;
final int NB_LITTERAL = 2;
identificateursOperandes = new Identificateur[NB_IDENTIFICATEUR];
litterauxOperandes = new Litteral[NB_LITTERAL];
} }
/** /**
* Calculer la valeur de cette expression à ce moment précis. * Calculer la valeur de cette expression à ce moment précis.
* Peut accéder au contexte. * Peut accéder au contexte.
* @return un Litteral de valeur du résultat de l'expression * @return un Litteral de valeur du résultat de l'expression
* @throws RuntimeException si le contexte n'est pas référencer
* dans la classe Expression
*/ */
public Litteral calculer() { public Litteral calculer() {
return null; if (contexteGlobal == null) {
throw new RuntimeException("Le contexte doit être référencé "
+ "dans la classe Expression");
}
return null;
} }
/* non javadoc /* non javadoc
@@ -48,7 +72,25 @@ public class Expression {
*/ */
@Override @Override
public String toString() { public String toString() {
return "Expression#toString() BOUCHON"; StringBuilder resultat = new StringBuilder("");
Identificateur affect = identificateursOperandes[INDEX_AFFECTATION];
resultat.append(affect == null ? "" : (affect.toString() + " = "));
Identificateur gaucheId = identificateursOperandes[INDEX_OPERANDE_G];
Litteral gaucheLitteral = litterauxOperandes[INDEX_OPERANDE_G];
resultat.append(gaucheId != null ? gaucheId.toString()
: gaucheLitteral.toString());
Identificateur droiteId = identificateursOperandes[INDEX_OPERANDE_D];
Litteral droiteLitteral = litterauxOperandes[INDEX_OPERANDE_D];
if (droiteId != null || droiteLitteral != null) {
resultat.append(" + ");
resultat.append(droiteId != null ? droiteId.toString()
: droiteLitteral.toString());
}
return resultat.toString();
} }
/** /**
@@ -57,22 +99,34 @@ public class Expression {
* et est possible une unique fois. * et est possible une unique fois.
* @param aReferencer référence du contexte global * @param aReferencer référence du contexte global
* @return <ul><li>true si le contexte a pu être référencé</li> * @return <ul><li>true si le contexte a pu être référencé</li>
* <li>true si aReferencer == contexte déjà référencer</li>
* <li>false si aReferencer est null</li> * <li>false si aReferencer est null</li>
* <li>false si un contexte est déjà référencer</li> * <li>false si un contexte est déjà référencer</li>
* </ul> * </ul>
*/ */
public static boolean referencerContexte(Contexte aReferencer) { public static boolean referencerContexte(Contexte aReferencer) {
if (aReferencer != null
&& (contexteGlobal == null || aReferencer == contexteGlobal)) {
contexteGlobal = aReferencer;
return true;
}
return false; return false;
} }
/** /**
* Détermine et créé une expression du bon type selon texteExpression. * Détermine et créé une expression du bon type selon texteExpression.
* Les types possibles sont ExpressionChaine ou ExpressionEntier.
* @param texteExpression texte suivant la syntaxe d'une expression * @param texteExpression texte suivant la syntaxe d'une expression
* @return l'expression du bon type correspondant à texteExpression * @return l'expression du bon type correspondant à texteExpression
* @throws InterpreteurException si texteExpression n'est pas valide * @throws InterpreteurException si texteExpression n'est pas valide
* ou amène à une incohérence de type * ou amène à une incohérence de type
*/ */
public static Expression determinerType(String texteExpression) { public static Expression determinerTypeExpression(String texteExpression) {
return null; String aTraiter = texteExpression.trim();
if (aTraiter.startsWith("$") || aTraiter.startsWith("\"")) {
return new ExpressionChaine(aTraiter);
} else {
return new ExpressionEntier(aTraiter);
}
} }
} }
@@ -5,6 +5,8 @@
package interpreteurlir.expressions; package interpreteurlir.expressions;
import interpreteurlir.InterpreteurException; import interpreteurlir.InterpreteurException;
import interpreteurlir.donnees.Identificateur;
import interpreteurlir.donnees.IdentificateurChaine;
import interpreteurlir.donnees.litteraux.Chaine; import interpreteurlir.donnees.litteraux.Chaine;
/** /**
@@ -18,15 +20,96 @@ import interpreteurlir.donnees.litteraux.Chaine;
public class ExpressionChaine extends Expression { public class ExpressionChaine extends Expression {
/** /**
* Initalise une expression de type Chaine avec les liens nécessaires à son * Initalise une expression de type Chaine
* calcule. * avec les liens nécessaires à son calcul.
* @param texteExpression texte suivant la syntaxe d'une expression * @param texteExpression texte suivant la syntaxe d'une expression
* @throws InterpreteurException si texteExpression n'est pas valide * @throws InterpreteurException si texteExpression n'est pas valide
* ou amène à une incohérence de type * ou amène à une incohérence de type
*/ */
public ExpressionChaine(String texteExpression) { public ExpressionChaine(String texteExpression) {
super(); super();
// TODO final String MESSAGE_ERREUR = "une expression ne peut être vide";
String gauche;
String droite;
String aTraiter = texteExpression;
/* chaîne null ou blanche */
if (aTraiter == null || aTraiter.isBlank()) {
throw new InterpreteurException(MESSAGE_ERREUR);
}
aTraiter = aTraiter.trim();
/* Traitement de la possible affectation */
int indexEgal = aTraiter.startsWith("$") ? aTraiter.indexOf('=') : -1;
if (indexEgal > -1) {
identificateursOperandes[INDEX_AFFECTATION] =
new IdentificateurChaine(aTraiter.substring(0, indexEgal));
aTraiter = aTraiter.substring(indexEgal + 1);
}
/* Traitement du nombre d'opérande */
int indexPlus = indexOperateur(aTraiter, '+');
gauche = aTraiter;
if (indexPlus > -1) {
gauche = aTraiter.substring(0, indexPlus);
droite = aTraiter.substring(indexPlus + 1, aTraiter.length());
initialiserOperande(droite, INDEX_OPERANDE_D);
}
initialiserOperande(gauche, INDEX_OPERANDE_G);
}
/**
* Détermine l'index de l'opérateur en dehors des constantes littérales
* @param aTraiter chaîne à traiter
* @param operateur opérateur à chercher hors guillemet
* @return index dans à traiter du plus sinon -1 si aucun plus
*/
public static int indexOperateur(String aTraiter, char operateur) {
char[] aTester = aTraiter.toCharArray();
int indexPlus;
int nbGuillemet = 0;
for (indexPlus = 0 ;
indexPlus < aTester.length
&& (aTester[indexPlus] != operateur || nbGuillemet % 2 != 0) ;
indexPlus++) {
if (aTester[indexPlus] == '"') {
nbGuillemet++;
}
}
return indexPlus >= aTester.length ? -1 : indexPlus;
}
/**
* Initialise l'opérande à sa place dans l'expression.
* @param operande représentation texte de l'opérande
* @param index index de l'operande parmi INDEX_OPERANDE_G
* et INDEX_OPERANDE_D
* @throws IllegalArgumentException si index non valide
*/
private void initialiserOperande(String operande, int index) {
if (INDEX_OPERANDE_G != index && INDEX_OPERANDE_D != index) {
throw new IllegalArgumentException("index invalide");
}
if (operandeEstLitteral(operande)) {
litterauxOperandes[index] = new Chaine(operande);
} else {
identificateursOperandes[index] =
new IdentificateurChaine(operande);
}
}
/**
* Détermine le genre de l'opérande (Chaine ou IdentificateurChaine).
* @param operande représentation texte de l'opérande
* @return true si operande est du genre Litteral sinon false
*/
private static boolean operandeEstLitteral(String operande) {
return operande.trim().startsWith("\"");
} }
/* non javadoc /* non javadoc
@@ -34,17 +117,38 @@ public class ExpressionChaine extends Expression {
*/ */
@Override @Override
public Chaine calculer() { public Chaine calculer() {
// TODO Auto-generated method stub Chaine valeur;
return null;
} super.calculer(); // exception levée si pas de contexte
/* non javadoc /* Détermine opérandeGauche */
* @see interpreteurlir.expressions.Expression#toString() Identificateur idGauche =
*/ identificateursOperandes[INDEX_OPERANDE_G];
@Override Chaine operandeG = (Chaine)(idGauche == null
public String toString() { ? litterauxOperandes[INDEX_OPERANDE_G]
// TODO Auto-generated method stub : contexteGlobal.lireValeurVariable(idGauche));
return "ExpressionChaine#toString() BOUCHON";
/* Détermine possible operandeDroite */
Identificateur idDroite =
identificateursOperandes[INDEX_OPERANDE_D];
Chaine operandeD = null;
if (idDroite != null || litterauxOperandes[INDEX_OPERANDE_D] != null) {
operandeD = (Chaine)(idDroite == null
? litterauxOperandes[INDEX_OPERANDE_D]
: contexteGlobal.lireValeurVariable(idDroite));
}
/* Calcul de la valeur */
valeur = operandeD == null ? operandeG
: Chaine.concatener(operandeG, operandeD);
/* Affectation si nécessaire */
if (identificateursOperandes[INDEX_AFFECTATION] != null) {
contexteGlobal.ajouterVariable(
identificateursOperandes[INDEX_AFFECTATION], valeur);
}
return valeur;
} }
} }
@@ -4,7 +4,12 @@
*/ */
package interpreteurlir.expressions.tests; package interpreteurlir.expressions.tests;
import static info1.outils.glg.Assertions.*;
import interpreteurlir.expressions.Expression; import interpreteurlir.expressions.Expression;
import interpreteurlir.expressions.ExpressionChaine;
import interpreteurlir.expressions.ExpressionEntier;
import interpreteurlir.Contexte;
/** /**
* Tests unitaires de {@link Expression} * Tests unitaires de {@link Expression}
@@ -15,5 +20,116 @@ import interpreteurlir.expressions.Expression;
* @author Lucas Vabre * @author Lucas Vabre
*/ */
public class TestExpression { public class TestExpression {
/** Jeu d'essai d'expression typée */
private Expression[] fixture = {
new ExpressionChaine("$chaine = \"texte\""),
new ExpressionChaine("$chaine=\"tata\""),
new ExpressionChaine(" $tata \t "),
new ExpressionChaine("\"une chaine de texte\""),
new ExpressionChaine("$chaine= \"toto\"+\"titi\""),
new ExpressionChaine("$chaine= $toto +\"titi\""),
new ExpressionChaine("$chaine= \"toto\"+ $titi"),
new ExpressionChaine("$chaine=$toto +$titi"),
new ExpressionChaine(" \"toto\"+\"titi\""),
new ExpressionChaine("$toto +\"titi\""),
new ExpressionChaine("\"toto\"+ $titi"),
new ExpressionChaine("$toto + $titi"),
// TODO expression entière
};
/**
* Tests unitaires de {@link Expression#referencerContexte(Contexte)}
*/
public void testReferencerContexte() {
Contexte reference = new Contexte();
Contexte[] contextes = {
null, reference, reference, new Contexte()
};
boolean[] resultatAttendu = { false, true, true, false };
System.out.println("\tExécution du test de "
+ "Expression#referencerContexte(Contexte)");
for (int numTest = 0 ; numTest < contextes.length ; numTest++) {
assertTrue( Expression.referencerContexte(contextes[numTest])
== resultatAttendu[numTest]);
}
}
/**
* Tests unitaires de {@link Expression#toString()}
*/
public void testToString() {
final String[] chaineAttendue = {
"$chaine = \"texte\"",
"$chaine = \"tata\"",
"$tata",
"\"une chaine de texte\"",
"$chaine = \"toto\" + \"titi\"",
"$chaine = $toto + \"titi\"",
"$chaine = \"toto\" + $titi",
"$chaine = $toto + $titi",
"\"toto\" + \"titi\"",
"$toto + \"titi\"",
"\"toto\" + $titi",
"$toto + $titi"
};
System.out.println("\tExécution du test de Expression#toString()");
for (int numTest = 0 ; numTest < chaineAttendue.length ; numTest++) {
assertEquivalence(chaineAttendue[numTest],
fixture[numTest].toString());
}
}
/**
* Tests unitaires de {@link Expression#determinerTypeExpression(String)}
*/
public void testDeterminerTypeExpression() {
final String[] TEXTE_EXPRESSION = {
/* Expression de type chaine */
"$chaine = \"texte\"",
"$chaine=\"tata\"",
" $tata \t ",
" \"une chaine de texte\"",
"$chaine= \"toto\"+\"titi\"",
" $chaine= $toto +\"titi\"",
"$chaine= \"toto\"+ $titi",
"$chaine=$toto +$titi",
" \"toto\"+\"titi\"",
"\t$toto +\"titi\"",
"\"toto\"+ $titi",
"$toto + $titi",
/* Expression de type Entier */
"78",
" entier",
"78 %89",
" entier- nombre",
"\t entier/78",
"entier = 78 ",
" nombre= nombre + 78",
" entier =78 *2"
// TODO expressionEntier
};
final int INDEX_DEBUT_ENTIER = 12;
System.out.println("\tExécution du test de "
+ "Expression#determinerTypeExpression(String)");
for (int numTest = 0; numTest < TEXTE_EXPRESSION.length ; numTest++) {
if (numTest < INDEX_DEBUT_ENTIER) {
assertTrue(Expression.determinerTypeExpression(
TEXTE_EXPRESSION[numTest]) instanceof ExpressionChaine);
} else {
assertTrue(Expression.determinerTypeExpression(
TEXTE_EXPRESSION[numTest]) instanceof ExpressionEntier);
}
}
}
} }
@@ -4,10 +4,17 @@
*/ */
package interpreteurlir.expressions.tests; package interpreteurlir.expressions.tests;
import static info1.outils.glg.Assertions.*;
import interpreteurlir.Contexte;
import interpreteurlir.InterpreteurException;
import interpreteurlir.donnees.IdentificateurChaine;
import interpreteurlir.donnees.litteraux.Chaine;
import interpreteurlir.expressions.Expression; import interpreteurlir.expressions.Expression;
import interpreteurlir.expressions.ExpressionChaine;
/** /**
* Tests unitaires de {@link Expression} * Tests unitaires de {@link ExpressionChaine}
* @author Nicolas Caminade * @author Nicolas Caminade
* @author Sylvan Courtiol * @author Sylvan Courtiol
* @author Pierre Debas * @author Pierre Debas
@@ -15,5 +22,123 @@ import interpreteurlir.expressions.Expression;
* @author Lucas Vabre * @author Lucas Vabre
*/ */
public class TestExpressionChaine { public class TestExpressionChaine {
/** Jeu de tests d'expression chaîne valides*/
private ExpressionChaine[] fixture = {
new ExpressionChaine("$chaine = \"texte\""),
new ExpressionChaine("$chaine=\"tata\""),
new ExpressionChaine(" $tata \t "),
new ExpressionChaine("\"une chaine de texte\""),
new ExpressionChaine("$chaine= \"toto\"+\"titi\""),
new ExpressionChaine("$chaine= $toto +\"titi\""),
new ExpressionChaine("$chaine= \"toto\"+ $titi"),
new ExpressionChaine("$chaine=$toto +$titi"),
new ExpressionChaine(" \"toto\"+\"titi\""),
new ExpressionChaine("$toto +\"titi\""),
new ExpressionChaine("\"toto\"+ $titi"),
new ExpressionChaine("$toto + $titi"),
new ExpressionChaine("\"ab=bc\""),
new ExpressionChaine("$chaine = \"ab+cd\"+$toto")
};
/**
* Tests unitaires de {@link ExpressionChaine#ExpressionChaine(String)}
*/
public void testExpressionChaineString() {
final String[] INVALIDES = {
null,
"",
"3,1415", "3.1415", "1.7976931348623157E308",
"45", "-89",
"tata + $toto",
"\"chaine\" = $vie",
"$chaine / \"tata\"",
"£", "$"
};
final String[] VALIDES = {
"$chaine = \"texte\"",
"$chaine=\"tata\"",
" $tata \t ",
"\"une chaine de texte\"",
"$chaine= \"toto\"+\"titi\"",
"$chaine= $toto +\"titi\"",
"$chaine= \"toto\"+ $titi",
"$chaine=$toto +$titi",
" \"toto\"+\"titi\"",
"$toto +\"titi\"",
"\"toto\"+ $titi",
"$toto + $titi",
"\"ab=bc\"",
"$chaine = \"ab+cd\"+$toto"
};
System.out.println("\tExécution du test de "
+ "ExpressionChaine#ExpressionChaine(String)");
for (String texteArgs : INVALIDES) {
try {
new ExpressionChaine(texteArgs);
echec();
} catch (InterpreteurException lancee) {
// empty
}
}
for (String texteArgs : VALIDES) {
try {
new ExpressionChaine(texteArgs);
} catch (InterpreteurException lancee) {
echec();
}
}
}
/**
* Tests unitaires de {@link ExpressionChaine#calculer()}
*/
public void testCalculer() {
final Chaine[] RESULTAT_ATTENDU = {
new Chaine("\"texte\""),
new Chaine("\"tata\""),
new Chaine("\"\""),
new Chaine("\"une chaine de texte\""),
new Chaine("\"tototiti\""),
new Chaine("\"valTototiti\""),
new Chaine("\"toto\""),
new Chaine("\"valToto\""),
new Chaine("\"tototiti\""),
new Chaine("\"valTototiti\""),
new Chaine("\"toto\""),
new Chaine("\"valToto\""),
new Chaine("\"ab=bc\""),
new Chaine("\"ab+cdvalToto\"")
};
System.out.println("\tExécution du test de "
+ "ExpressionChaine#calculer()");
/* Exception levée si contexte non référencé */
try {
fixture[0].calculer();
echec();
} catch (RuntimeException e) {
// vide
}
/* Création contexte (avec $toto = "valToto") et référencement */
Contexte contexteGlobal = new Contexte();
contexteGlobal.ajouterVariable(new IdentificateurChaine("$toto"),
new Chaine("\"valToto\""));
Expression.referencerContexte(contexteGlobal);
System.out.print("\tContexte initial : \n" + contexteGlobal);
for (int numTest = 0; numTest < RESULTAT_ATTENDU.length ; numTest++) {
System.out.println("\nCalcul de : " + fixture[numTest]);
assertEquivalence(fixture[numTest].calculer()
.compareTo(RESULTAT_ATTENDU[numTest]), 0);
System.out.println("\tContexte : \n" + contexteGlobal);
}
}
} }
@@ -0,0 +1,56 @@
/**
* Instruction.java 9 mai 2021
* IUT info1 2020-2021, pas de copyright, aucun droit
*/
package interpreteurlir.motscles.instructions;
import interpreteurlir.Contexte;
import interpreteurlir.expressions.Expression;
import interpreteurlir.motscles.Commande;
/**
* Instruction du langage LIR. Chaque instruction se caractérise par une
* expression et un contexte d'exécution
* @author Nicolas Caminade
* @author Sylvan Courtiol
* @author Pierre Debas
* @author Heïa Dexter
* @author Lucas Vabre
*/
public class Instruction extends Commande {
/** Contexte d'exécution de cette instruction */
protected Contexte contexteGlobal;
/** Expression qui sera exécutée par la commande */
protected Expression aExecuter;
/**
* Initialise une instruction à partir du contexte d'éxécution et de
* l'expression à exécuter
* @param arguments expression qui sera exécutée
* @param contexte global de l'application
*/
public Instruction(String arguments, Contexte contexte) {
super(arguments,contexte);
// arguments non utilisés pour Instruction générale
}
/*
* Non - javadoc
* @see interpreteurlir.motscles.Commande#executer()
*/
@Override
public boolean executer() {
return super.executer();
}
/*
* Non - javadoc
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return getClass().getSimpleName() + " " + aExecuter;
}
}
@@ -0,0 +1,58 @@
/**
* InstructionVar.java 9 mai 2021
* IUT info1 2020-2021, pas de copyright, aucun droit
*/
package interpreteurlir.motscles.instructions;
import interpreteurlir.Contexte;
import interpreteurlir.InterpreteurException;
import interpreteurlir.expressions.Expression;
import interpreteurlir.expressions.ExpressionChaine;
/**
* Instruction de déclaration et d'affectation de variables. La syntaxe de
* cette expression est de la forme var identificateur = expression. Si
* expression non renseignée, l'interpréteur affichera un message d'erreur ;
* l'instruction doit effectuer systématiquement une affectation.
* @author Nicolas Caminade
* @author Sylvan Courtiol
* @author Pierre Debas
* @author Heïa Dexter
* @author Lucas Vabre
*/
public class InstructionVar extends Instruction {
/**
* TODO comment initial state of the object
* @param arguments expression à exécuter
* @param contexte global de l'interpréteur
*/
public InstructionVar(String arguments, Contexte contexte) {
super(arguments, contexte);
if (arguments == null || arguments.isBlank()
|| ExpressionChaine.indexOperateur(arguments, '=') <= 0)
throw new InterpreteurException("erreur de syntaxe");
aExecuter = Expression.determinerTypeExpression(arguments.trim());
}
/*
* Non - javadoc
* @see interpreteurlir.motscles.instructions.Instruction#executer()
*/
@Override
public boolean executer() {
aExecuter.calculer();
return false;
}
/*
* Non - javadoc
* @see interpreteurlir.motscles.instructions.Instruction#toString()
*/
@Override
public String toString() {
return "var " + aExecuter;
}
}
@@ -0,0 +1,52 @@
/**
* TestInstruction.java 9 mai 2021
* IUT info1 2020-2021, pas de copyright, aucun droit
*/
package interpreteurlir.motscles.instructions.tests;
import interpreteurlir.Contexte;
import interpreteurlir.motscles.instructions.Instruction;
/**
* Tests unitaires des instructions
* @author Nicolas Caminade
* @author Sylvan Courtiol
* @author Pierre Debas
* @author Heïa Dexter
* @author Lucas Vabre
*/
public class TestInstruction {
/**
* Test du constructeur
*/
public static void testInstruction() {
System.out.println("Test du constructeur");
Instruction aTester = new Instruction("Bonjour", new Contexte());
System.out.println("==> OK\n");
}
/**
* Test de toString()
*/
public static void testToString() {
System.out.println("Test de toString()");
Instruction aTester = new Instruction("Bonjour", new Contexte());
if (!aTester.toString().equals("Instruction null"))
System.err.println("Echec du test");
else
System.out.println("==> OK\n");
System.out.println(aTester);
}
/**
* Lancement des tests
* @param args non utilisé
*/
public static void main(String[] args) {
testInstruction();
testToString();
}
}
@@ -0,0 +1,83 @@
/**
* TestInstructionVar.java 9 mai 2021
* IUT info1 2020-2021, pas de copyright, aucun droit
*/
package interpreteurlir.motscles.instructions.tests;
import interpreteurlir.Contexte;
import interpreteurlir.InterpreteurException;
import interpreteurlir.motscles.instructions.InstructionVar;
/**
* Tests unitaires de l'instruction var
* @author Nicolas Caminade
* @author Sylvan Courtiol
* @author Pierre Debas
* @author Heïa Dexter
* @author Lucas Vabre
*/
public class TestInstructionVar {
/** jeu de données pour tests */
public static final String[] VALIDES = {
"$toto = $tata", "entier=2+2", "$coucou = $toto + \"titi\"",
"anneeNaissance = 1898"
};
/**
* Test du constructeur InstructionVar
*/
public static void testInstructionVar() {
final String[] EXPRESSIONS_INVALIDES = {
"bonjour", "", null, "$toto $tata",
};
System.out.println("Test du constructeur\navec expressions invalides");
for (String aTester : EXPRESSIONS_INVALIDES) {
try {
new InstructionVar(aTester, new Contexte());
throw new RuntimeException("Echec du test");
} catch (InterpreteurException lancee) {
System.out.println(aTester + " ==> OK");
}
}
System.out.println("Avec expressions valides");
for (String aTester : VALIDES)
new InstructionVar(aTester, new Contexte());
System.out.println("Fin du test\n");
}
/**
* Test de toString
*/
public static void testToString() {
final String[] CHAINES_ATTENDUES = {
"var $toto = $tata", "var entier=2+2",
"var $coucou = $toto + \\\"titi\\\"",
"var anneeNaissance = 1898"
};
System.out.println("Test de toString()");
for (int i = 0 ; i < VALIDES.length ; i++) {
try {
assert VALIDES[i].toString().equals(CHAINES_ATTENDUES[i]);
} catch (AssertionError lancee) {
System.err.println("Echec du test à l'indice " + i);
}
}
System.out.println("Fin du test\n");
}
/**
* TODO comment method responsibilities
* @param args
*/
public static void main(String[] args) {
testInstructionVar();
testToString();
}
}