C'est vrai qu'une fonction doit être simple, et ne doit faire qu'une action simple. Si ton but est de te faciliter la vie, tu vas voir que la POO est faite pour toi
Bonsoir la famille vous allez bien?je suis nouveau sur ce forum et je le trouve super cool.J'ais un petit exercice la :Réalisez une classe de type compte en banque, en y intégrant deux méthodes, l’une déposant de l’argent,
l’autre en retirant, et dont vous vous assurerez que l’attribut solde ne puisse jamais être négatif.Dans la même classe écrivez une méthode d’accès au solde, qui retourne ce
dernier comme un entier, alors qu’il est stocké comme un réel.
ha oui tu trouves? moi par contre je le ferrais plus facilement en un bloc mais comme le livre ou j'ai tiré cet exercice aborde la notion de l'orientée objet donc j'ai encore un peu de mal avec les classes...
Bonjour a tous voila mon premier message ici et c'etait pour que vous jugiez le resultat de l'exercice sur les fonctions a deux arguments, voila je l'ai entierement fait moi meme, fait et refait et refait encore pour etre honnete mais j'ysuis arrivé ! alors voila :
#include <iostream>
using namespace std;
char signe('a');
void dessineRectangle(int l, int h)
{
for(int ligne(0); ligne < h; ligne++)
{
for(int colonne(0); colonne < l; colonne++)
{
cout << signe ;
}
cout << endl;
}
}
int main()
{
cout<<" choisissez votre signe afin de dessiner le rectangle"<< endl;
cin >> signe ;
int largeur, hauteur;
do
{
cout << "Largeur du rectangle ?" ;
cin >> largeur;
cout <<"Hauteur du rectangle?";
cin >> hauteur;
if (( largeur <0) || (hauteur <0))
{ cout<<"Erreure chiffre"<< endl;
}
} while ((largeur <0)|| (hauteur < 0));
dessineRectangle(largeur, hauteur);
system("pause");
return 0;
}
le "cahier des charges" demandait a la base simplement : de rajouter un message d'erreur si la hauteur ou la largeur est négative et un argument pour le symbole à utiliser dans le dessin. Mais je me suis dis qu'un simple message d'erreur etait un peu "trop simpliste" et j'ai donc fait la boucle qui ne valideralafonction quesi les deux chiffreentier sont positif,c'est plus complet je trouve, alors voila dites moiceque vous en pensez
Bon, c'est un exercice de plus d'un an, mais je suis nouveau ici et je fait les exercices passés,
Pour celui la j'ai repris la solution de TheSasukz je me suis permis d'ajouter les fonctions de boucle, pour m'entrainer a utiliser les streams et les listes. Je comprend pas le problème du dernier caractère qui est traité deux fois,
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <list>
using namespace std; // Ergonomie "maximum"
int main(){
// Déclaration et initialisation des variables "principales"
char v[30000], l(' ');
int i = 29999;
string fName(" ");
list<streampos> positions; // liste des pointeurs d'entrée de boucle
bool pass = false; // 2 variables pour passer les boucles avec 0 en entrée
int passCount = 0;
while (i >= 0) v[i--] = 0;
i = 0; // Préparation du "pseudo-pointeur"
cout << "EXERCICE CPP - INTERPRETEUR BRAINF." << endl;
cout << "Entrez le nom du fichier TXT source (sans extension)" << endl;
cin >> fName;
cout << endl << "> ";
string ext(fName+".txt"); // Rapide concaténation
ifstream iStr(ext.c_str()); // On ouvre le flux de fichier
if (iStr) {
while (iStr.good()) { // Tant que le fichier est "bon" à la lecture, on lit
iStr.get(l);
if (pass) { // Mode pass, si une boucle a 0 en entrée,
switch (l) { // on ignorre tout sauf les [ et les ]
case '[': passCount++; break; // On compte les boucles imbriquées dans la boucle a ignorer
case ']':
if (passCount > 0)
passCount--; // pour chaque boucle imbriquée, on ignore un point de sortie
else
pass = false; // et on repasse en mode normal lorsqu'on a trouvé la sortie
break;
}
} else {
switch (l) {
// Instructions de déplacement du pseudo-pointeur
case '<': if (i != 0) { i--; } break;
case '>': if (i != 29999) { i++; } break;
// Instructions de dé/incrémentation
case '+': v[i]++; break;
case '-': if (v[i] > 0) v[i]--; break;
// Instructions d'entrée/sortie de valeurs
case '.': cout << v[i]; break;
case ',': cin >> v[i]; break;
// Boucles
case '[':
if (v[i] > 0) // si on entre dans une boucle avec un compteur
positions.push_back(iStr.tellg()); // on ajoute son adresse dans la liste
else // si le compteur est a 0 à l'entréee,
pass = true; // on passe en mode de recherche de la sortie de boucle.
break;
case ']':
if (positions.empty()) // si on a un point de sortie mais qu'on a plus de point d'entrée...
cout << "erreur ] sans [";
else{
if (v[i] ==0) // si le compteur est a 0 on se debarrase du point d'entrée
positions.pop_back();
else{ // si le compteur est différent de 0, on recupère le point d'entrée dans la liste
list<streampos>::reverse_iterator posIter = positions.rbegin();
iStr.seekg(*posIter);
}
}
break;
}
}
l = ' ';
}
} else { // Si le fichier est illisible/introuvable
cout << endl << "ERREUR : Flux de fichier inutilisable" << endl;
}
cout << endl;
system("PAUSE");
return 0;
}
J'ai ajouté l=' ' a la fin de la boucle pour éviter que le dernier caractère soit traité deux fois mais ce n'est pas satisfaisant.
Je pense avoir trouvé, il faut que la fonction get(l) échoue pour que le test good soit faux, donc on fait une boucle de trop.
J'ai essayé de remplacer good par !eof mais ca ne marche pas non plus.
J'ai déplacé la fonction get a la fin de la boucle, la première boucle ne fait rien vu qu'on initialise a ' ' et l'état du fichier est correct au moment de le tester.
@CQui : quand tu as besoin d'informations par rapport à ta réalisation d'un exercice particulier, poste plutôt un nouveau sujet. Accessoirement cette solution a des choses à revoir :
Bonjour tout le monde, voici un petit exo que je trouve vraiment sympa, bien qu'assez complexe. Le but est de créer une machine à résoudre les énigmes de logique telle que la suivante :
Une bijouterie a été cambriolée. L'inspecteur a trois suspects: André, Bill et Charlie.
Voici ce qu'il a déduit de l'interrogatoire :
-L'un des trois au moins est coupable.
-Si André est coupable, au moins l'un des deux autres est innocent.
-Si Bill est innocent, Charlie l'est aussi.
-Il est impossible que André soit seul innocent.
-Si Charlie est innocent, Bill l'est aussi.
Qui est le coupable ?
Voici donc l'exercice Résolveur d'énigme, dans la catégorie Jeux.
Une des difficultés de cet exercice étant la manipulation d'assertions logiques, et parce qu'il est un peu long, il sera un peu guidé, mais rien ne vous empêche de trouver votre propre solution. Je suis également disponible pour répondre (même par MP si vous le souhaitez) à vos questions
Enfin, vous aurez probablement besoin d'implémenter d'autres fonctions que les principales qui vous sont suggérées. L'usage d'une classe n'apporte pas grand chose à cet exercice, vous êtes libres de tout encapsuler ou non
Par ailleurs, cet exercice vous amènera à manipuler les Piles/Stacks et les exceptions
Description :
Pour transcrire les hypothèses de l'énigme en assertions logiques (c'est a dire en phrases utilisant des connecteurs logiques), on utilisera la notation polonaise inversée ou notation post-fixée (https://fr.wikipedia.org/wiki/Notation_polonaise_inverse). Pour bien comprendre, voici des exemples de transcription en notation post-fixée :
(A ou B) et C donne: ( A B ou C et)
(A => B) et (C => D) donne: (A B => C D => et)
(Je peux rajouter des exemples si vous voulez)
La notation post-fixée allant naturellement de pair avec les piles, on écrira les propositions sous la forme
enum Element
{
False,
True,
Et,
Ou,
Non,
Implique,
Equivaut,
A,
B,
C
};
using Proposition = std::stack<Element>;
où l'énumérateur Elementcontient tous les éléments logiques qui apparaîtront dans nos propositions(A, B et C feront offices de variables).
Étape 1 :
Écrire une fonction var_libres prenant en paramètre une Proposition prop et renvoyant une Proposition contenant les variables de prop (c'est à dire les éléments différents de False/True/Et/Ou/Non/Implique/Equivaut).
Étape 2 :
On appelle environnement un ensemble de booléens associé aux variables. On rajoute donc la ligne :
using Environnement = std::vector<bool>;
Par exemple, si les variables sont [A, B, C] et l'environnement associé est [true, false, false], alors A vaut true, B vaut false et C vaut false.
Afin de pouvoir parcourir tous les environnement pouvant être associés aux variables, il faut maintenant définir une fonction incr prenant en paramètre un environnement et renvoyant l'environnement suivant dans l'ordre lexicographique.
Par exemple, voici une succession d'incrémentations pour un environnement à trois variables :
false false false
false false true
false true false
false true true
true false false
…
(je rappelle que vous avez le droit de me demander des explications plus précises, ce n'est pas forcément trivial )
Si l'environnement passé en paramètre est maximal (true true true), incr doit lancer une exception IncrMax.
Il faut également définir une fonction evaluequi prend en paramètre une Proposition et un Environnement, et doit renvoyer la valeur de vérité (true ou false) de la proposition, les variables étant évaluées grâce à l'Environnement.
Étape 3 :
On y est presque . Maintenant, il faut coder une fonction satisfiable qui prend une Proposition en paramètre, et qui teste tous les environnements possibles jusqu'à en trouver un tel que la Proposition soit vraie pour cet environnement. Cet Environnement est alors la valeur renvoyée.
S'il n'y en a aucun, la fonction doit lancer une exception Insatisfiable.
On définit enfin une tautologie comme une expression qui est toujours vraie, quelques soient les valeurs de ses variables (exemple : A ou (non A)), c'est à dire que son contraire est insatisfiable. La dernière fonction (dont on pourrait en fait se passer pour résoudre l'énigme) à écrire est alors la fonction tautologie, prenant une Proposition en paramètre, et vérifiant si c'est une tautologie. Si c'est le cas, elle lance une exception Tautologie. Sinon, elle renvoie un Environnement contre-exemple, c'est a dire qui rend la Proposition fausse.
Ultime Étape :
Maintenant, il ne reste plus qu'à écrire l’énigme sous forme de Proposition, et à utiliser la fonction tautologie pour déterminer le(s) coupable(s). Pour vérifier vos résultats, vous pouvez facilement résoudre l'énigme de tête
Vous pouvez, si vous le préférez, commencer par faire des tests avec les propositions suivantes :
- (P et (non P)) est insatisfiable.
- (P ou (non P)) est une tautologie.
- (P => Q) => ((non Q) => (non P)) est une tautologie (vous venez de démontrer le principe de contraposition).
- Edité par UnCodeurCommeUnAutre 10 août 2015 à 0:22:14
Il y a toujours un moyen de le faire. Il y a toujours un meilleur moyen de le faire.
@UnCodeurCommeUnAutre : poste un sujet sur le forum, selon le volume de code, soit un dépôt git, soit le code directement dans la page (du coupici ce sera plus souvent le dépôt git), et les gens le commenteront .
la classe d'erreurs std::invalid_argument (pour récupérer les exceptions dues à stoi, si ce n'est pas un nombre)
Il n'y a pas beaucoup de commentaires, je pourrais en rajouter si vous le voulez. J'ai implémenté toutes les fonctions proposées, en changeant quelques trucs :
le define n'est utilisé que pour définir les fonctions, pour les variables on utilise set (comme pour les modifier)
j'ai remplacé set! par set
l'opérateur "," renvoie un nombre qui identifie le tableau dans un autre tableau
les noms de variables/de fonctions doivent suivre la regex suivante : [a-zA-Z]*
l'opérateur de séquence (begin expr1 expr2 ...) est remplacé par (expr1 expr2 ...)
Je suis ouverts aux commentaires pour améliorer mon code
Il est un peu long, donc si vous avez un site pour le mettre à votre disposition ce serait volontiers, je pourrais le retirer de ce message car là il encombre un peu...
Merci d'avance !
main.cpp
#include <iostream>
#include <fstream>
#include <string>
#include "bloc.h"
using namespace std;
// Fonction pour afficher l'aide de l'exécutable
void help(char* s){
cout << "Interpréteur P'tit Langage 0.1" << endl;
cout << "Syntaxe : " << s << " file.ptl [options]" << endl;
cout << "Codes de retour :" << endl;
cout << "\t0 OK (tout s'est bien passé)" << endl;
cout << "\t1 ARGUMENTS INVALIDES (arguments trop nombreux)" << endl;
cout << "\t2 ERREUR FICHIERS (problème lors de l'ouverture ou de la lecture du fichier)" << endl;
cout << "\t3 ERREUR PROGRAMME (erreur dans le programme)" << endl;
}
int main(int argc, char* argv[]){
// En fonction du nombre d'argument
switch(argc){
case 1: // -> Aucun : on affiche l'aide, et on arrête le programme.
help(argv[0]);
return 0;
case 2: // -> Un : on exécute le contenu du fichier spécifié.
break;
default: // -> Autre : on affiche l'aide et on arrête le programme (code d'erreur 1).
cerr << "Vous avez saisi un nombre invalide d'arguments." << endl;
help(argv[0]);
return 1;
}
// Ouverture du fichier
ifstream file(argv[1]);
string text;
string line;
if(file){ // -> Ça marche, on lit le fichier.
while(getline(file, line)){
text += line + ' ';
}
} else { // -> Il y a eu une erreur, on l'affiche et on arrête le programme (code d'erreur 2).
cerr << "Ouverture du fichier " << argv[1] << " impossible." << endl;
return 2;
}
// ANALYSE SÉMANTIQUE DE LA PREMIÈRE COMMANDE
Bloc prgm(text);
// S'il y a eu une erreur, on quitte le programme.
if(variables["ERROR"] < 0) return 3;
// EXÉCUTION DE LA PREMIÈRE COMMANDE
int n = prgm.exec();
if(variables["ERROR"] < 0) return 3; // S'il y a eu une erreur, on quitte le programme.
if(show(prgm.getType())) cout << n << endl;
// ANALYSE SÉMANTIQUE ET EXÉCUTION DES AUTRES COMMANDES
while(prgm.getEnd() < text.size()-1){
prgm = Bloc(text, prgm.getEnd() + 1);
if(variables["ERROR"] < 0) return 3; // S'il y a eu une erreur, on quitte le programme.
n = prgm.exec();
if(variables["ERROR"] < 0) return 3; // S'il y a eu une erreur, on quitte le programme.
if(show(prgm.getType())) cout << n << endl;
}
return 0;
}
bloc.h
#ifndef BLOC_H
#define BLOC_H
#include <string>
#include <vector>
#include <iostream>
#include <map>
// Types de bloc
enum BlocType { // EXPLICATION SYNTAXE/NOM DE LA COMMANDE
NONE, // Bloc vide présent s'il y a des caractères blancs à la fin du programme
NOMBRE, // Nombre en dur (pas une expression) Ex : 256
VARIABLE, // Nom de variable Ex : var
ADDITION, // | +
SOUSTRACTION, // | ---\ Opérations pour lesquelles -
MULTIPLICATION, // | ---/ il faut calculer le résultat *
DIVISION, // | /
SET, // Assignation d'une valeur à une variable (il n'y a pas de déclaration) set
IF, // Condition : (if condition faisca sinonfaisca) if
AND, // ET logique dans une condition and
OR, // OU logique dans une condition or
NOT, // NON logique dans une condition not ou !
LT, // Plus petit que <
GT, // Plus grand que >
EQ, // Égal =
LE, // Plus petit ou égal <=
GE, // Plus grand ou égal >=
SEQUENCE, // Opérateur de séquence - Faire précéder nombres et variables d'un espace (expr1 expr2 expr3 ...)
WHILE, // Boucle tant que while
LET, // Déclaration de variables locales let
DEFINE, // Définition de fonction (define nomdelafonction param1 param2 ... expr)
FUNCTION, // Exécution de fonction (nomdelafonction param1 param2 ...)
QUIET, // Opérateur de séquence sans la sortie standard (quiet expr1 expr2 ...)
NUPLET, // Opérateur de création de couple ,
NTH // Opérateur d'accès à un des champs d'un couple (nth nieme liste)
};
// Fonction qui définit s'il faut montrer un type de bloc ou non
bool show(BlocType t){
switch(t){
case NOMBRE: // Renvoie la valeur numérique
case ADDITION: // Renvoie le résultat de l'opération
case SOUSTRACTION: // Renvoie le résultat de l'opération
case MULTIPLICATION: // Renvoie le résultat de l'opération
case DIVISION: // Renvoie le résultat de l'opération
case VARIABLE:
case LET:
case FUNCTION:
case NTH:
return true;
default: // Dans la plupart des cas, on n'affiche pas le résultat, car il n'a aucune signification
return false;
}
}
// Classe représentant un bloc de commandes, comme (+ 3 2) ou (+ (let ((x 3) (y 2)) (* x y)) (/ 9 4))
class Bloc {
public:
Bloc();
Bloc(std::string s, int b=0); // Constructeur. S = string à analyser; B = charactère de S à partir duquel commencer.
int exec(std::map<std::string, int> localVars=std::map<std::string, int>()); // Exécution du bloc de commandes.
int getEnd(){ return end; }; // Accesseur.
BlocType getType(){ return type; }; // Accesseur.
private:
std::vector<Bloc> blocs; // Sous bloc, paramètres de la commande
int beginning; // Caractère de “text” à partir duquel commence le bloc
int end; // Caractère de “text” où se finit le bloc
int number; // Nombre représenté par le bloc si c'en est un
std::string text; // Programme
std::string name; // Nom si c'est une variable
BlocType type; // Type du bloc
};
std::map<std::string, int> variables;
std::map<std::string, std::pair<std::vector<std::string>, Bloc> > fonctions; // -> std::map<nom_de_la_fonction, std::pair<noms_des_parametres, corps> >
std::vector<std::vector<int> > nuplets;
Bloc::Bloc(): blocs(), beginning(0), end(0), text(""), type(NONE){
//
}
// CONSTRUCTEUR / ANALYSE SÉMANTIQUE
Bloc::Bloc(std::string s, int b): blocs(), beginning(b), text(s){
bool firstp = true;
std::string command;
for(int i=beginning; i<text.size(); i++){
if(text[i] == ' ' || text[i] == '\n' || text[i] == '\n') continue;
if(text[i] == ')'){
if(firstp){
std::cerr << "Parenthèse ouvrante manquante." << std::endl;
variables["ERROR"] = -1;
}
end = i;
break;
}
if(firstp){
firstp = false;
// On commence un bloc "commande"
if(text[i] == '('){
i++;
while(text[i] != ' ' && text[i] != '\n' && text[i] != '\t' && text[i] != '('){
command += text[i];
i++;
}
if(command == "+") type = ADDITION;
else if(command == "-") type = SOUSTRACTION;
else if(command == "*") type = MULTIPLICATION;
else if(command == "/") type = DIVISION;
else if(command == "if") type = IF;
else if(command == "not" || command == "!") type = NOT;
else if(command == "and") type = AND;
else if(command == "or") type = OR;
else if(command == "<") type = LT;
else if(command == ">") type = GT;
else if(command == "=") type = EQ;
else if(command == "<=") type = LE;
else if(command == ">=") type = GE;
else if(command == "define") type = DEFINE;
else if(command == "quiet") type = QUIET;
else if(command == ",") type = NUPLET;
else if(command == "nth") type = NTH;
else if(command == "let"){
type = LET;
while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++;
if(text[i] != '('){
std::cerr << "LET : parenthèse ouvrante manquante; let doit être suivi de la liste des variables locales sous la forme : (let ((var1 val1) (var2 val2) ...) expr)" << std::endl;
variables["ERROR"] = -1;
return;
}
i++;
while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++;
while(text[i] != ')'){
if(text[i] != '('){
std::cerr << "LET : parenthèse ouvrante manquante; let doit être suivi de la liste des variables locales sous la forme : (let ((var1 val1) (var2 val2) ...) expr)" << std::endl;
variables["ERROR"] = -1;
return;
}
i++;
while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++;
Bloc b(text, i);
blocs.push_back(b); // Un bloc avec le nom de la variable
i = b.end + 1;
while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++;
b = Bloc(text, i);
blocs.push_back(b); // Un bloc avec la valeur à attribuer à la variable
i = b.end + 1;
while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++;
if(text[i] != ')'){
std::cerr << "LET : parenthèse fermante manquante après la déclaration de la variable locale “" << command << "”." << std::endl;
variables["ERROR"] = -1;
return;
}
i++;
while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++;
}
i++;
while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++;
Bloc b(text, i);
blocs.push_back(b);
i = b.end;
i++;
while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++;
if(text[i] != ')'){
std::cerr << "LET : parenthèse fermante manquante après la fin de la commande." << std::endl;
variables["ERROR"] = -1;
return;
}
if(blocs.size() % 2 != 1){
std::cerr << "LET : nombre incorrect de paramètres." << std::endl;
variables["ERROR"] = -1;
return;
}
end = i;
break;
} else if(command == ""){
type = SEQUENCE;
i--;
} else if(command == "while") type = WHILE;
else if(command == "set"){
type = SET;
command = "";
while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++;
// On lit le nom de la variable
while(text[i] != ' ' && text[i] != '\n' && text[i] != '\t'){
if((text[i] < 'a' || text[i] > 'z') && (text[i] < 'A' || text[i] > 'Z')){ // Les noms de variable ne peuvent contenir que des lettres
std::cerr << "SET : un nom de variable ne doit contenir que des lettres (minuscules ou majuscules)." << std::endl;
variables["ERROR"] = -1;
return;
}
command += text[i];
i++;
}
name = command; // On enregistre le nom de la variable.
Bloc b(text, i); // On analyse le bloc suivant, contenant la valeur à donner à la variable.
blocs.push_back(b);
i = b.end+1;
while(text[i] == ' ' || text[i] == '\n' || text[i] == '\t') i++;
if(text[i] != ')'){
std::cerr << "SET : trop d'arguments, la syntaxe est (set variable valeur)" << std::endl;
variables["ERROR"] = -1;
}
end = i;
break;
} else {
type = FUNCTION;
name = command;
}
} else { // C'est un nombre ou une variable
type = NOMBRE;
// On lit
while(text[i] != ' ' && text[i] != '\n' && text[i] != '\t' && text[i] != ')'){
command += text[i];
i++;
}
// On essaye de convertir en nombre
try {
number = std::stoi(command);
} catch(std::invalid_argument e){ // Si ça marche pas -> c'est une variable, on prend la valeur de la variable.
type = VARIABLE;
for(int i = 0; i<command.size(); i++){
if((command[i] < 'a' || command[i] > 'z') && (command[i] < 'A' || command[i] > 'Z')){ // Vérification que la variable ne contient que des caracères de l'alphabet
std::cerr << command << " : un nom de variable ne doit contenir que des lettres (minuscules ou majuscules)." << std::endl;
number = -1;
variables["ERROR"] = -1;
return;
}
}
name = command;
}
end = i-1;
break;
}
} else {
Bloc b(text, i);
blocs.push_back(b);
i = b.end;
}
}
if(firstp){
type = NONE;
end = text.size()-1;
} else if(end == text.size()-1 && text[end] != ')'){
std::cerr << "Parenthèse fermante manquante." << std::endl;
variables["ERROR"] = -1;
}
if(type == IF){
if(blocs.size() < 2){
std::cerr << "IF : Argument(s) manquant(s). Syntaxe : (if condition faisci [sinonfaisca])" << std::endl;
variables["ERROR"] = -1;
} else if(blocs.size() > 3){
std::cerr << "IF : Trop d'arguments. Syntaxe : (if condition faisci [sinonfaisca])" << std::endl;
variables["ERROR"] = -1;
}
}
if(type == NOT){
if(blocs.size() > 1){
std::cerr << "NOT : Trop d'arguments. Syntaxe : (not condition) ou (! condition)" << std::endl;
variables["ERROR"] = -1;
} else if(blocs.size() == 0){
std::cerr << "NOT : Argument manquant. Syntaxe : (not condition) ou (! condition)" << std::endl;
variables["ERROR"] = -1;
}
}
if(type == OR && blocs.size() < 2){
std::cerr << "OR : Argument(s) manquant(s). Syntaxe : (or condition1 condition2 [condition3 ...])" << std::endl;
variables["ERROR"] = -1;
}
if(type == AND && blocs.size() < 2){
std::cerr << "AND : Argument(s) manquant(s). Syntaxe : (and condition1 condition2 [condition3 ...])" << std::endl;
variables["ERROR"] = -1;
}
if(type == LT || type == GT || type == EQ || type == LE || type == GE){
if(blocs.size() < 2){
std::cerr << "COMPARAISON : Argument(s) manquant(s). Syntaxe : (comparaison expr1 expr2)" << std::endl;
variables["ERROR"] = -1;
} else if(blocs.size() > 2){
std::cerr << "COMPARAISON : Trop d'arguments. Syntaxe : (comparaison expr1 expr2)" << std::endl;
variables["ERROR"] = -1;
}
}
if(type == WHILE){
if(blocs.size() < 2){
std::cerr << "WHILE : Argument(s) manquant(s). Syntaxe : (while condition expr)" << std::endl;
variables["ERROR"] = -1;
} else if(blocs.size() > 2){
std::cerr << "WHILE : Trop d'arguments. Syntaxe : (while condition expr)" << std::endl;
variables["ERROR"] = -1;
}
}
if(type == DEFINE){
if(blocs.size() < 2){
std::cerr << "DEFINE : Pas assez d'arguments. Syntaxe : (define nomdelafonction [param1 [param2 [...]]] expr)" << std::endl;
variables["ERROR"] = -1;
}
for(int i=0; i<blocs.size()-1; i++){
if(blocs[i].type != VARIABLE){
std::cerr << "DEFINE : tous les arguments sauf le dernier doivent être des noms type variable. Erreur pour l'argument : " << i+1 << "." << std::endl;
variables["ERROR"] = -1;
return;
}
}
}
}
// EXÉCUTION
int Bloc::exec(std::map<std::string, int> localVars){
int n;
bool m;
switch(type){
case NOMBRE:
return number;
case VARIABLE:
if(localVars.find(name) != localVars.end()) return localVars[name];
else if(variables.find(name) != variables.end()) return variables[name];
else {
variables["ERROR"] = -1;
std::cerr << "Variable " << name << " indéfinie." << std::endl;
break;
}
case ADDITION:
n = 0;
for(int i=0; i<blocs.size(); i++){
n += blocs[i].exec(localVars);
}
return n;
case SOUSTRACTION:
n = blocs[0].exec(localVars);
for(int i=1; i<blocs.size(); i++){
n -= blocs[i].exec(localVars);
}
return n;
case MULTIPLICATION:
n = 1;
for(int i=0; i<blocs.size(); i++){
n *= blocs[i].exec(localVars);
}
return n;
case DIVISION:
n = blocs[0].exec(localVars);
for(int i=1; i<blocs.size(); i++){
n /= blocs[i].exec(localVars);
}
return n;
case SET:
n = blocs[0].exec(localVars);
variables[name] = n;
return n; // On renvoie la nouvelle valeur de la variable.
case IF:
if(blocs[0].exec(localVars) != 0){
n = blocs[1].exec(localVars);
if(show(blocs[1].type)) std::cout << n << std::endl;
} else if(blocs.size() > 2){
n = blocs[2].exec(localVars);
if(show(blocs[2].type)) std::cout << n << std::endl;
}
break;
case NOT:
return blocs[0].exec(localVars) == 0;
case OR:
m = blocs[0].exec(localVars);
for(int i=1; i<blocs.size(); i++){
m = (m || (blocs[i].exec(localVars) != 0));
}
return m;
case AND:
m = blocs[0].exec(localVars);
for(int i=1; i<blocs.size(); i++){
m = (m && (blocs[i].exec(localVars) != 0));
}
return m;
case LT:
return blocs[0].exec(localVars) < blocs[1].exec(localVars);
case GT:
return blocs[0].exec(localVars) > blocs[1].exec(localVars);
case EQ:
return blocs[0].exec(localVars) == blocs[1].exec(localVars);
case LE:
return blocs[0].exec(localVars) <= blocs[1].exec(localVars);
case GE:
return blocs[0].exec(localVars) >= blocs[1].exec(localVars);
case SEQUENCE:
for(int i=0; i<blocs.size(); i++){
n = blocs[i].exec(localVars);
if(show(blocs[i].type)) std::cout << n << std::endl;
}
return n;
case WHILE:
while(blocs[0].exec(localVars) != 0){
n = blocs[1].exec(localVars);
if(show(blocs[1].type)) std::cout << n << std::endl;
}
break;
case LET:
for(int i=0; i<blocs.size()-1; i+=2){
localVars[blocs[i].name] = blocs[i+1].exec(localVars);
}
return blocs[blocs.size()-1].exec(localVars);
case DEFINE:
name = blocs[0].name;
if(fonctions.find(name) != fonctions.end()){
std::cerr << "DEFINE : Redéfinition de la fonction : " << name << "." << std::endl;
variables["ERROR"] = -1;
break;
}
fonctions[name] = std::pair<std::vector<std::string>, Bloc>(std::vector<std::string>(), blocs[blocs.size()-1]);
for(int i=1; i<blocs.size()-1; i++){
fonctions[name].first.push_back(blocs[i].name);
}
break;
case FUNCTION:
if(fonctions.find(name) != fonctions.end()){
if(blocs.size() != fonctions[name].first.size()){
std::cerr << "Nombre de paramètres invalide pour la fonction " << name << " : " << fonctions[name].first.size() << " paramètres attendus, " << blocs.size() << "reçus." << std::endl;
variables["ERROR"] = -1;
return -1;
}
for(int i=0; i<blocs.size(); i++){
localVars[fonctions[name].first[i]] = blocs[i].exec(localVars);
}
return fonctions[name].second.exec(localVars);
} else {
std::cerr << "Fonction non définie : " << name << "." << std::endl;
variables["ERROR"] = -1;
return -1;
}
case QUIET:
for(int i=0; i<blocs.size()-1; i++){
blocs[i].exec(localVars);
}
return blocs[blocs.size()-1].exec(localVars);
case NUPLET:
n = nuplets.size();
nuplets.push_back(std::vector<int>());
for(int i=0; i<blocs.size(); i++){
nuplets[n].push_back(blocs[i].exec(localVars));
}
return n; // On renvoie l'endroit où on a enregistré le couple dans le tableau nuplets.
case NTH:
return nuplets[blocs[1].exec(localVars)][blocs[0].exec(localVars)];
}
return -1;
}
#endif
- Edité par Moi moi moi 6 novembre 2015 à 19:09:07
Découpe ton code, des fonctions de 150 lignes, c'est (au moins) 10 fois trop long, et là on en a une qui fait 220 lignes. Sans parler de l'inextensibilité complète du bordel que ça produit. Et ta classe bloc (nom très mal choisi) a beaucoup trop de responsabilités différentes : 1 classe = 1 unique responsabilité (SRP).
Pour la classe bloc, elle n'a pour moi qu'une seule responsabilité : elle représente une instruction et permet de l'exécuter.
Quedal.
Elle reçoit un programme en entrée et fait :
l'analyse syntaxique,
l'analyse sémantique,
l'exécution.
Ce qu'on veut c'est :
générer la listes des lexemes à partir du texte (minimum une classe, en vrai beaucoup plus parce qu'on doit qualifier les lexemes),
générer l'AST à partir des lexemes (une classe de génération + un type par possibilité de noeud d'AST), ce que tu appelles "BlocType", ça justifie bien chacun une classe quasiment,
faire un visiteur qui à partir d'un AST correct produit le résultat (encore une classe).
je viens de finir les niveaux 1 à 4 de l'exercice Biblio++ de Germino, je souhaiterais avoir vos avis et commentaires dessus.
L'organisation des fichiers de données est la suivante :
fichier livre :
chaque ligne correspond à un livre
l'organisation d'une ligne est la suivante : N°Livre 1ou0 idEmprunteur/Titre/Auteur/Genre/DateEmprunt/DateRetour (Le 1 ou 0 correspond à : est ce que le livre est emprunté ou non)
fichier membre :
chaque ligne correspond à un membre
l'organisation d'une ligne est la suivante : ID/Nom/Prenom
L'organisation du programme est la suivante :
Il y a quatre classes :
Bibliothèque : qui gère le chargement des fichiers et les interactions avec l'utilisateur
Livre : qui gère les paramètres et l'affichage des livres
Membres : qui gère les paramètres et l'affichage des membres
Date : qui gère les dates. (je débute dans le C++, du coup j'ai préféré ne pas utiliser la classe de boost car je n'ai encore jamais utilisé cette bibliothèque)
A côté de ces classes, j'utilise des fonctions pour la saisie sécurisé issu du tutoriel de ooprog.
Le code :
Il est un peu long . Si certain ont un endroit ou je peux le mettre pour éviter d'encombrer le forum.
Quand tu as beaucoup de code, il est préférable de le mettre sur un dépôt type github pour permettre une lecture plus aisée. De plus, quand tu veux demander des commentaires sur un exercice, il est préférable d'ouvrir un nouveau sujet.
Concernant ton code, d'un point de vue conception :
la duplication ecritureStream + operator<< et lectureStream + operator>> est une (des multiples) connerie montrée par le cours moisi d'OC, ça multiplie les éléments de l'interface et ruine l'ISP (principes SOLID),
un Emprunt et un Livre sont deux choses différentes (et doivent donc bénéficier chacune d'une classe),
on n'inclut des headers que lorsqu'ils sont nécessaires (s'il n'est pas nécessaire dans un header, il n'a rien à faire là et doit être inclus dans le source uniquement).
Voilà, il y a déjà du boulot et tu t'en épargneras en utilisant un cours de C++ correct.
le cours en ligne de @gbdivers (en cours d'écriture), pour les problèmes liés à des incompréhensions qui ne sont dues à un manque d'étude ou juste une difficulté de ton côté, il y a ce post de forum pour répertorier, sinon il y a le forum pour poster tes question,
je voudrais réaliser une petit jeu, voici son principe :
- tirer un mot aléatoire dans un dictionnaire compose d'une centaine de mots,
-le donner a l'utilisateur en désordre; il doit trouver le mot correct en écrivant ce mot quand on lui aura demandé,
-compter le nombre de coups : passé 10 essais on lui affiche la réponse;
-compter le nombre de fois : au terme des cinq premiers tours on lui affiche son score sur 5;
-on lui redemande s'il veut encore jouer une autre partie par oui ou non.
*Voici le lien du dictionnaire à télécharger.
J'ai vraiment beaucoup essayé ce exercice mais le dictionnaire m'a loupé et le comptage de coups et je me rends aussi compte que sur presque tous les exercices que je cherche sur Internet je retrouve toujours ces bêtes de drôle.
Je veux aussi quelques petites explications pour mieux comprendre le code via des commentaires ou a la fin mais c'est mieux avec des commentaires, je remercierai vraiment la personne qui m'aidera a résoudre cet exercice.
Merci d'avance.
- Edité par StephaneWamba 2 janvier 2017 à 20:22:22
C'est plutôt amusant de conseiller un cours de C++ dont on explique en long, en large et en travers sur le forum qu'il est obsolète et apprends un paquet de trucs à ne surtout pas faire, en particulier quand on débute.
Merci pour ton information, car je ne parcours pas le forum en long, en large et en travers.
Cependant je ne suis pas sur que ton intervention va aider Stephane.
Et la réponse a sa question ce trouve en partie dans le lien que je lui ai suggéré, de plus si ce cours est tout pouris comme tu le signale il faudrais peut être qu'il soit retiré.
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C
Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C