This commit is contained in:
2025-03-13 12:01:03 +01:00
parent d39124f928
commit f53b5791dd
571 changed files with 12844 additions and 320 deletions

View File

@@ -0,0 +1 @@
export CLASSPATH=".:/usr/share/java/junit.jar:/usr/share/java/hamcrest-core.jar"

View File

@@ -0,0 +1,20 @@
/**
* Classe Abstraite pour modéliser les éléments d'un programme après analyse lexicale (ou tokenization en franglais).
*
* Le programme est une succession de lexèmes ou jetons après analyse lexicale. Par exemple, un jeton contenant le nom d'une variable,
* un jeton pour un symbole d'une opération etc.
*
* Une classe concrète étendant cette classe permet de modéliser un type de jeton, et d'adapter le traitement selon le type du jeton
* lors de l'analyse syntaxique / compilation.
*
* On utilise simplement toString pour retrouver le texte initial.
*
* @author Florent Madelaine
*/
public abstract class AbstractToken {
}

View File

@@ -0,0 +1,23 @@
import java.util.Deque;
import java.util.ArrayDeque;
public class Exemple{
public static void main(String[] args){
// 3 + 4 × (2 1)
// pas de parenthèse encore, je fais 3 + 4 * 2
Deque<AbstractToken> expression = new ArrayDeque<AbstractToken>();
expression.addLast(new TokenConstant(3));
expression.addLast(new TokenOperator(Operator.ADD));
expression.addLast(new TokenConstant(4));
expression.addLast(new TokenOperator(Operator.MUL));
expression.addLast(new TokenConstant(2));
StringBuilder b = new StringBuilder();
for(AbstractToken t : expression ){
b.append(t.toString());
}
System.out.println(b.toString());
}
}

View File

@@ -0,0 +1,60 @@
import java.util.Deque;
import java.util.ArrayDeque;
public class ExempleSY1{
public static void main(String[] args){
// 3 + 4 * 2
// doit donner 342*+
ArrayDeque<AbstractToken> expression = new ArrayDeque<AbstractToken>();
expression.addLast(new TokenConstant(3));
expression.addLast(new TokenOperator(Operator.ADD));
expression.addLast(new TokenConstant(4));
expression.addLast(new TokenOperator(Operator.MUL));
expression.addLast(new TokenConstant(2));
ShuntingYard se1 = new ShuntingYard(expression);
ShuntingYard se2 = new ShuntingYard(expression.clone());
// à la main
System.out.println("-----à la main -----");
System.out.println(se1);
se1.shuntFromInput(); //step1
System.out.println(se1);
se1.pushToStack(); //step2
System.out.println(se1);
se1.shuntFromInput(); //step3
System.out.println(se1);
se1.pushToStack(); //step4
System.out.println(se1);
se1.shuntFromInput(); //step5
System.out.println(se1);
se1.shuntFromStack(); //step6
System.out.println(se1);
se1.shuntFromStack(); //step7
System.out.println(se1);
System.out.println("-----------FIN à la main---------------");
// avec l'algo
System.out.println("-----avec l'algo -----");
System.out.println(se2);
se2.shunting();
System.out.println(se2);
se2.shunting();
System.out.println(se2);
se2.shunting();
System.out.println(se2);
se2.shunting();
System.out.println(se2);
se2.shunting();
System.out.println(se2);
se2.shunting();
System.out.println(se2);
se2.shunting();
System.out.println(se2);
// se2.shunting();
// System.out.println(se2);
// se2.shunting();
// System.out.println(se2);
}
}

View File

@@ -0,0 +1,43 @@
import java.util.Deque;
import java.util.ArrayDeque;
public class ExempleSY2{
public static void main(String[] args){
// 3 + 4 * 2 1
// doit donner 342*+1-
Deque<AbstractToken> expression = new ArrayDeque<AbstractToken>();
expression.addLast(new TokenConstant(3));
expression.addLast(new TokenOperator(Operator.ADD));
expression.addLast(new TokenConstant(4));
expression.addLast(new TokenOperator(Operator.MUL));
expression.addLast(new TokenConstant(2));
expression.addLast(new TokenOperator(Operator.SUB2));
expression.addLast(new TokenConstant(1));
ShuntingYard se = new ShuntingYard(expression);
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
}
}

View File

@@ -0,0 +1,48 @@
import java.util.Deque;
import java.util.ArrayDeque;
public class ExempleSY3{
public static void main(String[] args){
// 3 + 4 × (2 1)
// doit donner 3421-*+
Deque<AbstractToken> expression = new ArrayDeque<AbstractToken>();
expression.addLast(new TokenConstant(3));
expression.addLast(new TokenOperator(Operator.ADD));
expression.addLast(new TokenConstant(4));
expression.addLast(new TokenOperator(Operator.MUL));
expression.addLast(new TokenSeparator(Separator.LB));
expression.addLast(new TokenConstant(2));
expression.addLast(new TokenOperator(Operator.SUB2));
expression.addLast(new TokenConstant(1));
expression.addLast(new TokenSeparator(Separator.RB));
ShuntingYard se = new ShuntingYard(expression);
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
}
}

View File

@@ -0,0 +1,105 @@
import java.util.Deque;
import java.util.ArrayDeque;
public class ExempleSY4{
public static void main(String[] args){
// utilisation de l'algo de Fortan sur l'expression de ExempleSY3
// (( 3 ))+(( 4 )*( ( (( 2 ))-(( 1)))))
// doit donner 3421-*+ mais le parseur actuel ne sait pas gérer plusieurs parenthèses.
Deque<AbstractToken> expression = new ArrayDeque<AbstractToken>();
expression.addLast(new TokenSeparator(Separator.LB));
expression.addLast(new TokenSeparator(Separator.LB));
expression.addLast(new TokenConstant(3));
expression.addLast(new TokenSeparator(Separator.RB));
expression.addLast(new TokenSeparator(Separator.RB));
expression.addLast(new TokenOperator(Operator.ADD));
expression.addLast(new TokenSeparator(Separator.LB));
expression.addLast(new TokenSeparator(Separator.LB));
expression.addLast(new TokenConstant(4));
expression.addLast(new TokenSeparator(Separator.RB));
expression.addLast(new TokenOperator(Operator.MUL));
expression.addLast(new TokenSeparator(Separator.LB));
expression.addLast(new TokenSeparator(Separator.LB));
expression.addLast(new TokenSeparator(Separator.LB));
expression.addLast(new TokenSeparator(Separator.LB));
expression.addLast(new TokenConstant(2));
expression.addLast(new TokenSeparator(Separator.RB));
expression.addLast(new TokenSeparator(Separator.RB));
expression.addLast(new TokenOperator(Operator.SUB2));
expression.addLast(new TokenSeparator(Separator.LB));
expression.addLast(new TokenSeparator(Separator.LB));
expression.addLast(new TokenConstant(1));
expression.addLast(new TokenSeparator(Separator.RB));
expression.addLast(new TokenSeparator(Separator.RB));
expression.addLast(new TokenSeparator(Separator.RB));
expression.addLast(new TokenSeparator(Separator.RB));
expression.addLast(new TokenSeparator(Separator.RB));
ShuntingYard se = new ShuntingYard(expression);
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
}
}

View File

@@ -0,0 +1,73 @@
import java.util.Deque;
import java.util.ArrayDeque;
public class ExempleSY5{
public static void main(String[] args){
// 3 + 4 * 2 / ( 1 5 ) ^ 2 ^ 3
// doit donner 342*15-23^^/+
Deque<AbstractToken> expression = new ArrayDeque<AbstractToken>();
expression.addLast(new TokenConstant(3));
expression.addLast(new TokenOperator(Operator.ADD));
expression.addLast(new TokenConstant(4));
expression.addLast(new TokenOperator(Operator.MUL));
expression.addLast(new TokenConstant(2));
expression.addLast(new TokenOperator(Operator.DIV));
expression.addLast(new TokenSeparator(Separator.LB));
expression.addLast(new TokenConstant(1));
expression.addLast(new TokenOperator(Operator.SUB2));
expression.addLast(new TokenConstant(5));
expression.addLast(new TokenSeparator(Separator.RB));
expression.addLast(new TokenOperator(Operator.EXP));
expression.addLast(new TokenConstant(2));
expression.addLast(new TokenOperator(Operator.EXP));
expression.addLast(new TokenConstant(3));
ShuntingYard se = new ShuntingYard(expression);
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
}
}

View File

@@ -0,0 +1,35 @@
/**
* Enum pour représenter les opérations sur les entiers (pas d'autre type manipulé pour l'instant).
*
* Attention : l'ordre de l'énumération sert à coder la précédence des opérateurs.
*
* @author Florent Madelaine
*/
public enum Operator {
SUB1 ("-", true),
EXP ("^", false),
MUL ("*", true),
DIV ("/", true),
ADD ("+", true),
SUB2 ("-", true);
private final String str; // String in original program
private final boolean isLeftAssociative;
public boolean isLeftAssociative(){
return isLeftAssociative;
}
private Operator(String str, boolean b){
this.str=str;
this.isLeftAssociative=b;
}
@Override
public String toString(){
return this.str;
}
}

View File

@@ -0,0 +1,214 @@
# Questions.
ce fichier sert à indiquer les réponses après chaque question, indiquez aussi svp vos nom et prénom.
il faut rédiger au format markdown svp.
En particulier, le code est à mettre entre deux triple quotes.
Les sources sont disponibles en ligne sur le site des TPs.
Vous devez rendre sur devoir une archive tar.gz contenant un répertoire test/ contenant les fichiers java (pas les .class) et ce fichier Questions.md.
```bash
tar -czvf test.tar.gz test/
```
Nom : Pourchot
Prénom : Adrian
## Programmation défensive.
1. [2 points] Préparez la javadoc pour les 4 méthodes suivantes de ShuntingYard
shuntFromInput()
shuntFromStack()
pushToStack()
crushParenthesis()
Il faut prévoir un comportement adapté en cas de problème.
Par exemple shuntFromInput ne devrait transférer que des TokenConstant et des TokenVariable
et pushToStack ne devrait transférer que des TokenOperator ou des parenthèse gauche.
Indiquez la javadoc dans ce fichier juste après cette ligne, en recopiant la première ligne de déclaration de chaque méthode.
---
```java
/**
* Envoie la premiere constante ou variables de la file d'entrée vers la file de sortie.
* Si le Token récupéré n'est pas TokenConstant ou un TokenVariable, il y a 2 cas possible:
* Soit il s'agit d'un TokenOperator ou d'un TokenSeparator de gauche, dans ce cas on replace l'élément extrait au départ de la file d'entrée
* puis on fait appel à la méthode shuntFromStack() plutôt que celle-ci.
* Soit il s'agit d'un TokenSeparator de droite, dans ce cas on la replace au départ de ola file d'entrée et on fait appel à la méthode crushParenthesis()
* pour la supprimer.
*/
public void shuntFromInput() {
/**
* Envoie le dernier élément de la pile stack vers la file de sortie.
*/
public void shuntFromStack() {
/**
* Envoie le premier opérateur ou parenthèse gauche de la file d'entrée vers la pile stack.
* Si le Token récupéré n'est pas un TokenOperator ou un TokenSeparator de gauche, il y a 2 cas possible:
* Soit le Token est un TokenConstant ou un TokenVariable, dans ce cas on replace le Token extrait au départ de la file d'entrée
* puis on fait appel à la méthode shuntFromInput() plutôt que celle-ci.
* Soit il s'agit d'un TokenSeparator de droite, dans ce cas on la replace au départ de ola file d'entrée et on fait appel à la méthode crushParenthesis()
* pour la supprimer.
*/
public void pushToStack(){
/**
* Supprime le premier élément de la file d'entrée et le dernier de la pile stack.
* @exception IllegalStateException Renvoyer si il y s'agit d'un cas particulier.
*/
public void crushParenthesis(){
```
---
2. [2 points] Proposez le changement adapté au code de shuntFromInput et de pushToStack
donnez le code ci-dessous.
---
public void shuntFromInput() {
x=this.input.getFirst();
if(x instanceof(TokenConstant)||x instanceof(TokenVariable))
this.output.addLast(x);
else if(x instanceof(TokenOperator)){
this.input.addFirst(x);
shuntFromStack();
}
else if(x.getSeparator().equals(Separator.LB)){
this.input.addFirst(x);
shuntFromStack();
}
else{
this.input.addFirst(x);
crushParenthesis();
}
}
---
## Invariant
3. [2 points] Quels sont les invariants des méthodes suivantes?
shuntFromInput()
shuntFromStack()
pushToStack()
---
---
## Debug
4. [1 point] Faite tourner les tests avec le fichier JUnit fourni (TestShuntingYard1.java)
Quels tests sont passés avec succès?
Quels tests ne sont pas passés avec succès?
---
Test réussi:
1) pushStack(TestShuntingYard1)
Test échoué:
1) shuntingTest1(TestShuntingYard1)
2) shuntInput(TestShuntingYard1)
3) shuntStack(TestShuntingYard1)
4) CandyCrush(TestShuntingYard1)
---
5. [7 points] Pour chaque test non passé, indiquez le bug que vous observez en français.
Puis pour chaque test non passé, proposez un changement de code.
Il faut indiquer le numéro de la ligne dans le fichier initial (vous pouvez le renommer en ajoutant OLD au bout avant de changer le fichier dans une copie).
recopier la ligne, puis indiquez en dessous la nouvelle ligne.
Il faut expliquer en français dans un commentaire ci-dessous en quoi ce changement consiste.
Dans le fichier changé, il faut ajouter en commentaire à la fin //BUGFIX 0 où le numéro correspond à la notation ci-dessous.
En dessous je vous donne une exemple en cadeau.
---
### Test concerné :
aucun, ceci est un BUGFIX gratuit pour indiquer le format attendu
Le test d'arrêt de ShuntingYard est incorrect, car il faut lever l'exception seulement quand l'input et la pile sont vide, pas l'un ou l'autre.
ShuntingYard.java line 73 (avant):
```java
return (this.input.isEmpty() || this.stack.isEmpty());
```
devient
ShuntingYard.java line 73 (après):
```java
return (this.input.isEmpty() && this.stack.isEmpty()); //BUG FIX 0
```
### Test concerné :
???
```java
// BUGFIX 1
```
```java
// BUGFIX 2
```
---
1) shuntingTest1(TestShuntingYard1): On observe que le shunting c'est arrêter car la file d'entrée et la pile stack étaient vide ce qui ne devrait pas être le cas.
2) shuntInput(TestShuntingYard1): On observe que l'AbstractToken n'est pas trouvé dans la file alors qu'il devrait.
3) shuntStack(TestShuntingYard1): Même chose que pour shuntInput, un AbstractToken n'est pas trouvé dans la pile alors qu'il devrait.
4) CandyCrush(TestShuntingYard1): On observe qu'une parenthèse droite est trouvé alors qu'il devrait s'agir d'une parenthèse gauche.
---
6. [6 points] Complétez le fichier de test TestShuntingYard2.java
a) [1 point] Proposez un test JUnit pour attraper un NullPointerException lorsqu'on appelle shuntFromInput() sur un input vide.
indiquez le nom de ce test ici :
---
---
b) [1 point] Proposez un test JUnit pour attraper l'exception adaptée lorsqu'on appelle shuntFromInput() sur un input dont le prochain token n'est pas un TokenVariable ou un TokenConstant.
indiquez le nom de ce test ici :
---
---
c) [2 points] Pour l'exemple ExempleSY2.java, proposez la liste des instructions primitives correspondant à l'algo de Dijkstra.
(i.e. les primitives que shunting devrait appeller si code convenablement).
---
```java
```
---
d) [3 points]
Proposez un test JUnit correspondant à l'exemple ExempleSY2.java
Expliquez bien votre démarche.
indiquez le nom de ce test ici, puis expliquez votre démarche :
---
---

View File

@@ -0,0 +1,47 @@
Ce projet concerne l'agorithme de Dijkstra présenté sur wikipedia
ici :
https://en.wikipedia.org/wiki/Shunting_yard_algorithm
=================================================================
Ce projet contient le présent fichier et une image et des fichiers java
README.txt descripton des fichiers de ce répertoire
Shunting_yard.svg.png image tiré de la page wikipedia de l'algo
=================================================================
Ce projet concerne les fichiers java suivant.
AbstractToken.java type abstrait pour les token (jeton) d'une expression.
TokenConstant.java hérite du précédent, jeton pour les constantes
TokenVariable.java jeton pour les variables
ReservedWord.java type énuméré pour les mots réservés qui ne peuvent être des noms de variable.
TokenOperator.java jeton pour les opérateurs
Operator.java type énuméré pour les symboles d'opérateurs, utilisé par TokenOperator
TokenSeparator.java jeton pour les séparateurs
Separator.java type énuméré pour les symboles de séparateurs, utilisé par TokenSeparator
Exemple.java exemple d'expression construite
ShuntingYard.java classe fournissant l'algorithme de parsing de Dijkstra
ExempleSY1.java exemple d'usage de Shunting Yard
ExempleSY2.java exemple d'usage de Shunting Yard
ExempleSY3.java exemple d'usage de Shunting Yard
ExempleSY4.java exemple d'usage de Shunting Yard
ExempleSY5.java exemple d'usage de Shunting Yard
================================================================
Pour l'examen proprement dit.
Questions.md fichier avec le barème et les questions
TestShuntingYard1.java fichier de test fourni
TestShuntingYard2.java fichier de test à compléter

View File

@@ -0,0 +1,23 @@
/**
* Enum pour représenter les mots réservés du langage qui ne peuvent pas être des noms de variables.
*
*
* @author Florent Madelaine
*/
public enum ReservedWord {
INT ("int"),
FUNC ("function");
private final String str; // String in original program
private ReservedWord(String str){
this.str=str;
}
@Override
public String toString(){
return this.str;
}
}

View File

@@ -0,0 +1,28 @@
/**
* Enum pour représenter les "séparateurs" dans le programme.
*
* @author Florent Madelaine
*/
public enum Separator {
LB ("("),
RB (")"),
COMMA (","),
SCL (";"),
LCB ("{"),
RCB ("}"),
LSB ("["),
RSB ("]");
private final String str; // String in original program
private Separator(String str){
this.str=str;
}
@Override
public String toString(){
return this.str;
}
}

View File

@@ -0,0 +1,273 @@
import java.util.Deque;
import java.util.ArrayDeque;
/**
* Classe implémentant l'algorithme proposé par Dijkstra en 1961 pour transformer une expression en notation infixe, en expression postfixe.
* https://en.wikipedia.org/wiki/Shunting_yard_algorithm
*
* Le constructeur prend en entrée l'entrée de l'algorithme (input) qui sera une file de AbstractToken et initialise
* une pile pour les opérateurs et séparateurs, et une file de sortie.
* Pour uniformiser, tout est modélisé avec l'interface Deque pour des AbstractToken.
*
* En pratique les seuls mouvements entre ces trois structures de données sont faits par trois primitives :
* shuntFromInput() (input vers output)
* shuntFromStack() (stack vers output)
* pushToStack() (input vers stack)
*
* L'algorithme fonctionne par analogie au rangement des wagons dans une gare de triage (shunting yard veut dire gare de triage).
*
* output ================== input
* \\ //
* \ /
* \/
* ||
* stack
*
* Le dessin en ASCII ci-dessus a été qualifié de "Jackson Pollock" du crobar par Luc Hernandez.
* Pour un exemple plus explicite : regardez svp le dessin "Shunting_yard.svg.png"
*
*
* Les constantes et les variables sont envoyées de droite à gauche avec shuntFromInput
* Les symboles d'opérations ou de séparation sont envoyés sur la pile avec pushToStack
* puis envoyés en sortie avec shuntFromStack quand c'est le bon moment.
*
* pour les opérateurs, en gros tout se décide avec la priorité des opérations
* En cas d'égalité on regarde si l'opérateur est associatif à gauche :
* ceci est le cas des 4 opérations binaires * \/ + - mais pas de l'exponentiation ^ (associativité à droite).
* Ainsi a^b^c sera interprété convenablement comme a^(b^c)
*
* @author Florent Madelaine
*/
public class ShuntingYard {
/**
*
*
*/
private Deque<AbstractToken> input;
private Deque<AbstractToken> output;
private Deque<AbstractToken> stack;
public ShuntingYard(Deque<AbstractToken> input){
this.input = input;
this.output = new ArrayDeque<AbstractToken>();
this.stack = new ArrayDeque<AbstractToken>();
}
public Deque<AbstractToken> getInput(){
return this.input;
}
public Deque<AbstractToken> getOutput(){
return this.stack;
}
public Deque<AbstractToken> getStack(){
return this.output;
}
// input and stack are empty
public boolean isOver(){
return (this.input.isEmpty() || this.stack.isEmpty()); //BUG FIX 1
}
//
// output <---------------- input
//
//
// stack
/**
* Envoie la premiere constante ou variables de la file d'entrée vers la file de sortie.
* Si le Token récupéré n'est pas TokenConstant ou un TokenVariable, il y a 2 cas possible:
* Soit il s'agit d'un TokenOperator ou d'un TokenSeparator de gauche, dans ce cas on replace l'élément extrait au départ de la file d'entrée
* puis on fait appel à la méthode shuntFromStack() plutôt que celle-ci.
* Soit il s'agit d'un TokenSeparator de droite, dans ce cas on la replace au départ de la file d'entrée et on fait appel à la méthode crushParenthesis()
* pour la supprimer.
*/
public void shuntFromInput() {
x=this.input.getFirst();
if(x instanceof(TokenConstant)||x instanceof(TokenVariable))
this.output.addLast(x);
else if(x instanceof(TokenOperator)){
this.input.addFirst(x);
shuntFromStack();
}
else if(x.getSeparator().equals(Separator.LB)){
this.input.addFirst(x);
shuntFromStack();
}
else{
this.input.addFirst(x);
crushParenthesis();
}
}
// output <--- input
// \
// |
// stack
/**
* Envoie le dernier élément de la pile stack vers la file de sortie.
*/
public void shuntFromStack() {
this.output.addFirst(this.stack.removeLast());
}
// output ---------- input
// /
// V
// stack
/**
* Envoie le premier opérateur ou parenthèse gauche de la file d'entrée vers la pile stack.
* Si le Token récupéré n'est pas un TokenOperator ou un TokenSeparator de gauche, il y a 2 cas possible:
* Soit le Token est un TokenConstant ou un TokenVariable, dans ce cas on replace le Token extrait au départ de la file d'entrée
* puis on fait appel à la méthode shuntFromInput() plutôt que celle-ci.
* Soit il s'agit d'un TokenSeparator de droite, dans ce cas on la replace au départ de ola file d'entrée et on fait appel à la méthode crushParenthesis()
* pour la supprimer.
*/
public void pushToStack(){
this.stack.addFirst(this.input.getFirst());
}
// output ) input
// ^
// ( <------| both to be destroyed
// stack
//
// throws IllegalStateException si ce n'est pas exactement ce cas.
/**
* Supprime le premier élément de la file d'entrée et le dernier de la pile stack.
* @exception IllegalStateException Renvoyer si il y s'agit d'un cas particulier.
*/
public void crushParenthesis(){
this.stack.removeLast();
this.input.removeFirst();
}
// does one step of Dijkstra Shunting algorithm
// if is is done it throws the exception
public void shunting(){
if (isOver()) throw new IllegalStateException("the shunting is over, since both the input and the stack are empty.");
else if (this.input.isEmpty()){
if (this.stack.getFirst() instanceof TokenSeparator){
TokenSeparator s = (TokenSeparator) this.stack.getFirst();
if (s.getSeparator().equals(Separator.LB)){
throw new IllegalArgumentException("the shunting is over with a parenthesis mismatch extra left bracket");}
}
else // should be an operator
shuntFromStack();
}
else if (this.input.getFirst() instanceof TokenConstant) {
shuntFromInput();
shuntFromInput();
}
// else
if (this.input.getFirst() instanceof TokenVariable) {
shuntFromInput();
}
else if (this.input.getFirst() instanceof TokenSeparator) {
TokenSeparator s = (TokenSeparator) this.input.getFirst();
// test si LB left bracket
if (s.getSeparator().equals(Separator.LB)){
pushToStack();
}
else if (s.getSeparator().equals(Separator.RB)){
if(stack.isEmpty()) throw new IllegalArgumentException("the shunting is over with a parenthesis mismatch extra right bracket");
else {
if (this.stack.getFirst() instanceof TokenOperator){
shuntFromStack(); // should be the operator concerned by parenthesis
}
else {// it is a separator
crushParenthesis(); // we discard the parenthesis.
}
}
}
}
else if (this.input.getFirst() instanceof TokenOperator) {
if (this.stack.isEmpty()){
pushToStack();
}
else if (this.stack.getFirst() instanceof TokenSeparator){
TokenSeparator s = (TokenSeparator) this.stack.getFirst();
pushToStack();
}
else if (this.stack.getFirst() instanceof TokenOperator){
TokenOperator o = (TokenOperator) this.input.getFirst();
TokenOperator o2 = (TokenOperator) this.stack.getFirst();
if (o2.takesPrecedenceOver(o)){
shuntFromStack();
}
else pushToStack();// shuntFromInput();// input takes precedence
}
}
}
@Override
public String toString(){
StringBuilder b = new StringBuilder();
b.append("\t\t\t\t");
for(AbstractToken t : this.input ){
b.append(t.toString());
}
b.append(" :input\noutput: ");
for(AbstractToken t : this.output ){
b.append(t.toString());
}
b.append("\n\t\t stack: ");
for(AbstractToken t : this.stack ){
b.append(t.toString());
}
b.append("\n");
b.append("--------------------------------------------------------------\n");
return b.toString();
}
public static void main(String[] args){
// 3 + 4 × (2 1)
// pas de parenthèse encore, je fais 3 + 4 * 2
Deque<AbstractToken> expression = new ArrayDeque<AbstractToken>();
expression.addLast(new TokenConstant(3));
expression.addLast(new TokenOperator(Operator.ADD));
expression.addLast(new TokenConstant(4));
expression.addLast(new TokenOperator(Operator.MUL));
expression.addLast(new TokenSeparator(Separator.LB));
expression.addLast(new TokenConstant(2));
expression.addLast(new TokenOperator(Operator.SUB2));
expression.addLast(new TokenConstant(1));
expression.addLast(new TokenSeparator(Separator.RB));
ShuntingYard se = new ShuntingYard(expression);
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
System.out.println(se);
se.shunting();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@@ -0,0 +1,179 @@
import java.util.Deque;
import java.util.ArrayDeque;
import static org.junit.Assert.assertTrue; // import static : une facilité offerte depuis java5 (pas besoin de mettre le préfixe)
import static org.junit.Assert.assertFalse; //
import static org.junit.Assert.assertSame; //
import static org.junit.Assert.assertNotSame; //
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertArrayEquals;
import org.junit.Test;
/**
* Une classe pour faire des tests sur la classe ShuntingYard avec JUnit
*/
public class TestShuntingYard1 {
/**
* ShuntInput déplace un token depuis input vers output
*
*/
@Test
public void shuntInput(){
Deque<AbstractToken> expression = new ArrayDeque<AbstractToken>();
expression.addLast(new TokenConstant(3));
ShuntingYard se = new ShuntingYard(expression);
AbstractToken t1 = se.getInput().getFirst();
se.shuntFromInput();
AbstractToken t2 = se.getOutput().getLast();
assertSame(t1,t2);
}
/**
* PushStack déplace un token depuis input vers stack
*
*/
@Test
public void pushStack(){
Deque<AbstractToken> expression = new ArrayDeque<AbstractToken>();
expression.addLast(new TokenConstant(3));
expression.addLast(new TokenOperator(Operator.ADD));
expression.addLast(new TokenConstant(4));
ShuntingYard se = new ShuntingYard(expression);
se.shuntFromInput();
AbstractToken t1 = se.getInput().getFirst();
se.pushToStack();
AbstractToken t2 = se.getStack().getFirst();
assertSame(t1,t2);
}
/**
* ShuntFromStack déplace un token depuis stack vers output
*
*/
@Test
public void shuntStack(){
Deque<AbstractToken> expression = new ArrayDeque<AbstractToken>();
expression.addLast(new TokenConstant(3));
expression.addLast(new TokenOperator(Operator.ADD));
expression.addLast(new TokenConstant(4));
ShuntingYard se = new ShuntingYard(expression);
se.shuntFromInput();
se.pushToStack();
se.shuntFromInput();
AbstractToken t1 = se.getStack().getFirst();
se.shuntFromStack();
AbstractToken t2 = se.getOutput().getLast();
assertSame(t1,t2);
}
/**
* crushParenthesis écrase les parenthèses quand stack est une LB
* et input est un RB
*/
@Test
public void CandyCrush(){
Deque<AbstractToken> expression = new ArrayDeque<AbstractToken>();
expression.addLast(new TokenSeparator(Separator.LB));
expression.addLast(new TokenConstant(2));
expression.addLast(new TokenOperator(Operator.SUB2));
expression.addLast(new TokenConstant(1));
expression.addLast(new TokenSeparator(Separator.RB));
ShuntingYard se = new ShuntingYard(expression);
se.pushToStack();
se.shuntFromInput();
se.pushToStack();
se.shuntFromInput();
se.shuntFromStack();
//prêt pour enlever les parenthèses.
AbstractToken t1 = se.getStack().getFirst();
TokenSeparator s1 = (TokenSeparator) t1;
int sizeStackbefore = se.getStack().size();
AbstractToken t2 = se.getInput().getFirst();
TokenSeparator s2 = (TokenSeparator) t2;
int sizeInputbefore = se.getInput().size();
assertEquals(Separator.LB,s1.getSeparator());
assertEquals(Separator.RB,s2.getSeparator());
se.crushParenthesis();
int sizeStackafter = se.getStack().size();
int sizeInputafter = se.getInput().size();
assertEquals(sizeStackbefore-1,sizeStackafter);
assertEquals(sizeInputbefore-1,sizeInputafter);
}
/**
* shunbtingTest1 vérifie que tout se passe bien pour l'exemple de ExempleSY1
*/
@Test
public void shuntingTest1(){
ArrayDeque<AbstractToken> expression = new ArrayDeque<AbstractToken>();
expression.addLast(new TokenConstant(3));
expression.addLast(new TokenOperator(Operator.ADD));
expression.addLast(new TokenConstant(4));
expression.addLast(new TokenOperator(Operator.MUL));
expression.addLast(new TokenConstant(2));
// moralement on veut tester que les trois structures de données sont les mêmes de manière synchrone entre ceci
// ShuntingYard se1 = new ShuntingYard(expression);
// se1.shuntFromInput(); //step1
// se1.pushToStack(); //step2
// se1.shuntFromInput(); //step3
// se1.pushToStack(); //step4
// se1.shuntFromInput(); //step5
// se1.shuntFromStack(); //step6
// se1.shuntFromStack(); //step7
// et cela
// ShuntingYard se2 = new ShuntingYard(expression);
// se2.shunting(); //step1
// Pour tester on utilise la facilité permettant de comparer élément pas élément deux tableaux.
// assertArrayEquals("Inputs are not the same",se1.getInput().toArray(),se2.getInput().toArray());
// assertArrayEquals("stacks are not the same",se1.getStack().toArray(),se2.getStack().toArray());
// assertArrayEquals("Output are not the same",se1.getOutput().toArray(),se2.getOutput().toArray());
ShuntingYard se1 = new ShuntingYard(expression);
ShuntingYard se2 = new ShuntingYard(expression.clone());// on clone l'expression, car sinon l'input est le même pour les deux exemples
assertArrayEquals("Inputs are not the same",se1.getInput().toArray(),se2.getInput().toArray());
assertArrayEquals("stacks are not the same",se1.getStack().toArray(),se2.getStack().toArray());
assertArrayEquals("Output are not the same",se1.getOutput().toArray(),se2.getOutput().toArray());
se1.shuntFromInput(); //step1
se2.shunting(); //step1
assertArrayEquals("Inputs are not the same",se1.getInput().toArray(),se2.getInput().toArray());
assertArrayEquals("stacks are not the same",se1.getStack().toArray(),se2.getStack().toArray());
assertArrayEquals("Output are not the same",se1.getOutput().toArray(),se2.getOutput().toArray());
se1.pushToStack(); //step2
se2.shunting(); //step2
assertArrayEquals("Inputs are not the same",se1.getInput().toArray(),se2.getInput().toArray());
assertArrayEquals("stacks are not the same",se1.getStack().toArray(),se2.getStack().toArray());
assertArrayEquals("Output are not the same",se1.getOutput().toArray(),se2.getOutput().toArray());
se1.shuntFromInput(); //step3
se2.shunting(); //step3
assertArrayEquals("Inputs are not the same",se1.getInput().toArray(),se2.getInput().toArray());
assertArrayEquals("stacks are not the same",se1.getStack().toArray(),se2.getStack().toArray());
assertArrayEquals("Output are not the same",se1.getOutput().toArray(),se2.getOutput().toArray());
se1.pushToStack(); //step4
se2.shunting(); //step4
assertArrayEquals("Inputs are not the same",se1.getInput().toArray(),se2.getInput().toArray());
assertArrayEquals("stacks are not the same",se1.getStack().toArray(),se2.getStack().toArray());
assertArrayEquals("Output are not the same",se1.getOutput().toArray(),se2.getOutput().toArray());
se1.shuntFromInput(); //step5
se2.shunting(); //step5
assertArrayEquals("Inputs are not the same",se1.getInput().toArray(),se2.getInput().toArray());
assertArrayEquals("stacks are not the same",se1.getStack().toArray(),se2.getStack().toArray());
assertArrayEquals("Output are not the same",se1.getOutput().toArray(),se2.getOutput().toArray());
se1.shuntFromStack(); //step6
se2.shunting(); //step6
assertArrayEquals("Inputs are not the same",se1.getInput().toArray(),se2.getInput().toArray());
assertArrayEquals("stacks are not the same",se1.getStack().toArray(),se2.getStack().toArray());
assertArrayEquals("Output are not the same",se1.getOutput().toArray(),se2.getOutput().toArray());
se1.shuntFromStack(); //step7
se2.shunting(); //step7
assertArrayEquals("Inputs are not the same",se1.getInput().toArray(),se2.getInput().toArray());
assertArrayEquals("stacks are not the same",se1.getStack().toArray(),se2.getStack().toArray());
assertArrayEquals("Output are not the same",se1.getOutput().toArray(),se2.getOutput().toArray());
}
}

View File

@@ -0,0 +1,22 @@
import java.util.Deque;
import java.util.ArrayDeque;
import static org.junit.Assert.assertTrue; // import static : une facilité offerte depuis java5 (pas besoin de mettre le préfixe)
import static org.junit.Assert.assertFalse; //
import static org.junit.Assert.assertSame; //
import static org.junit.Assert.assertNotSame; //
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertArrayEquals;
import org.junit.Test;
/**
* Une classe pour faire des tests sur la classe ShuntingYard avec JUnit
*/
public class TestShuntingYard2 {
}

View File

@@ -0,0 +1,30 @@
import java.util.Objects;
/**
* Jeton pour les constantes
*
* sert uniquement aux entiers, pas d'autre type pour l'instant
*
*
* @author Florent Madelaine
*/
public class TokenConstant extends AbstractToken {
private int value;
public TokenConstant (int i){
Objects.requireNonNull(i, "i must not be null");
this.value=i;
}
public int getValue(){
return this.value;
}
@Override
public String toString(){
return String.valueOf(this.value);
}
}

View File

@@ -0,0 +1,39 @@
import java.util.Objects;
/**
* Jeton pour les opérateurs
*
* sert uniquement à des opérations entières, pas d'autre type pour l'instant.
*
*
* @author Florent Madelaine
* @see Operators.java
*/
public class TokenOperator extends AbstractToken{
private Operator o;
public TokenOperator(Operator o){
Objects.requireNonNull(o, "o must not be null");
this.o=o;
}
public Operator getOperator(){
return this.o;
}
public boolean takesPrecedenceOver(TokenOperator to2){
return (this.o.ordinal() < to2.getOperator().ordinal()
||
((this.o.ordinal() == to2.getOperator().ordinal())
&&
to2.getOperator().isLeftAssociative()));
}
@Override
public String toString(){
return this.o.toString();
}
}

View File

@@ -0,0 +1,30 @@
import java.util.Objects;
/**
* Jeton pour les séparateurs
*
* parenthèses pour des expressions, etc.
*
* @author Florent Madelaine
* @see Separator.java
*/
public class TokenSeparator extends AbstractToken{
private Separator s;
public TokenSeparator(Separator s){
Objects.requireNonNull(s, "s must not be null");
this.s=s;
}
public Separator getSeparator(){
return this.s;
}
@Override
public String toString(){
return this.s.toString();
}
}

View File

@@ -0,0 +1,49 @@
import java.util.Objects;
/**
* Jeton pour les variables
*
* sert uniquement à des variables entières, pas d'autre type pour l'instant.
*
*
* The general rules for naming variables are:
*
* Names can contain letters and digits
* Names must begin with a letter
* Names should start with a lowercase letter, and cannot contain whitespace
* Names are case-sensitive ("myVar" and "myvar" are different variables)
* Reserved words cannot be used as names
*
*
* @author Florent Madelaine
* @see ReservedWords.java
*/
public class TokenVariable extends AbstractToken {
private final static String regexp="[a-z][0-9a-zA-Z]*";
private String variableName; // String in original program
public TokenVariable (String s){
Objects.requireNonNull(s, "s must not be null");
for (ReservedWord k : ReservedWord.values()){
if (k.toString().equals(s)){
throw new IllegalArgumentException("Illegal variable name, attempt to use reserved keyword " + k.toString());
}
}
if (! s.matches(this.regexp)){
throw new IllegalArgumentException("Illegal variable name, name should start with a lower case letter followed potentially by digits or other letters lower or upper case.");
}
else {
this.variableName=s;
}
}
@Override
public String toString(){
return this.variableName;
}
}