Accueil > > > CALCULETTE (PEUT ÊTRE GRAPHIQUE UN JOURS ^^)
CALCULETTE (PEUT ÊTRE GRAPHIQUE UN JOURS ^^)
Information sur la source
Description
mon programme décompose la chaine de caractère principale en un arbre (avec une structure) avec un algorithme récursif. Il est capable de calculer les expressions de bases avec la gestion des priorités et des parenthèses Il reconnais, les lettres de l'alphabet minuscule comme paramètres et les fonction exp,sin, cos, tan, asin,.... (les fonctions de math.h, on peux facilement en rajouter) finalement il calcule a partir de l'arbre.
Source
-
- #include<stdlib.h>
- #include<stdio.h>
- #include<string.h>
- #include<ctype.h>
- #include<stdlib.h>
- #include<math.h>
-
- #define _XOPEN_SOURCE 600 /* or #define _ISOC99_SOURCE */
- #define maxP 1024 //maximum de parentheses externes d'un calcul.
- #define MAX 2048
- #define MAXarg 1024
-
-
- typedef struct noeud {
- char node;
- char fct[4]; // pour pouvoir distinguer facilement les fonctions, comme sinus, des signes.
- struct noeud * parent;
- struct noeud * filsG;
- struct noeud * filsD;
- double val;
- char sVal;
- float exposant;
-
- } noeud;
-
-
- noeud * arbre(char *chaine, noeud * parent);
- void afficher_arbre ( noeud * root);
- double calculer( noeud *root);
- void ajouter_lettre(char * chaine, char lettre); //décale la chaine et ajoute la lettre au debut.
- void repere_fonctions(char * chaine);
- int par(char*chaine);//retourne l'indice dans la chaine de la parenthese qui ferme la premiere (toujours le premier caractere.)
- void signe_implicite(char * chaine); // corrige les '*' implicites devant les parentheses
- char * enleveParenthese(char *chaine);
-
-
-
- /** ***********************//** ***********************//** *********//** ***********************/
- noeud * creerNoeud(noeud * parents)
- {
- noeud * nNoeud=malloc(sizeof(noeud));
- nNoeud->filsD=NULL;
- nNoeud->filsG=NULL;
- nNoeud->val=0;
- nNoeud->node='\0';
- nNoeud->sVal='\0';
- //nNoeud->fct[0]='\0';
- //printf("noeud cree.\n");
- nNoeud->parent=parents;
- if(parents!=NULL)
- {
- if(parents->filsG!=NULL)
- {
- if(parents->filsD!=NULL)
- {
- printf("NULL Il y a un noeud qui est fiere de sa virilite... il voudrais un troisieme fils :D \n");
- return NULL;
- }
- parents->filsD=nNoeud;
- //printf("noeudD cree.\n");
- return nNoeud;
- }
- parents->filsG=nNoeud;
- //printf("noeudG cree.\n");
- return nNoeud;
- }
- else
- //printf("root cree.\n");
- return nNoeud;
- }
-
- /** ***********************//** ***********************//** ***********************//** ***********************//** ***********************//** ***********************/
-
-
-
-
-
-
-
-
-
- int chx[MAXarg]={0};
-
- int main(){
-
- chx[0]=0;chx[2]=1;/*
- printf("choisisez l'affichage(mettre 1 pour oui( 0 pour on) dans l'ordre):\n\t'0'=>commentaires\n\t'1'=>commentaires complementaire\n\t'2'=>utile pour le debogage(conseille)\n\t'3'=>pour le debogage le reste en vrac (deconseille :D)" );
- scanf("%d%d%d%d",&chx[0],&chx[1],&chx[2],&chx[3]);*/
- noeud * root=NULL;
- char chaine[MAX];
- //chaine=malloc(sizeof(chaine)+1);
- printf("coucou, entre ton calcul.\n");
- scanf("%s",chaine);
- root=arbre(chaine,root);
-
- printf("afficher arbre:\n");
- afficher_arbre (root);
- printf("\nle resultat est %f\n",calculer(root));
- printf("\n");
- return 0;
- }
-
- noeud * arbre(char *chaine,noeud *parent){
- char *chaineG;
- char *chaineD;
- noeud * root;
- float f1=0;
-
-
- root = creerNoeud(parent);
- int i;
- printf("la chaine est :%s\n",chaine);
- if(chx[0]==1){printf("\t\t=======initialisation=========");}
- chaine=enleveParenthese(chaine);
- repere_fonctions(chaine); // met des parentheses au tour des fonctions definies et des parametres
- signe_implicite(chaine); // corrige les '*' implicites devant les parentheses
- if(chx[2]==1){ printf("chaine avec tous les signes et les parentheses en extra:%s\n",chaine);}
- chaine=enleveParenthese(chaine); // protege des cas type (((1+2)))
- if(chx[3]==1){ printf("chaine les parentheses aux extremitees:%s\n",chaine);}
-
- /** décomposer la chaine en "S1 signe S2 " */
-
- /** étape 1 : mise en boite des parentheses.*/
- if(chx[0]==1){printf("\t\t=================mise en boite des parentheses==============\n");}
- int cpt=0, par[maxP],j=0; //dans le tableau par on met les addresses (dans la chaine "chaine",as les pointeurs) des premieres parentheses externes
-
- for (i=0;(chaine[i]!='\0');i++)
- {
- if (chaine[i]=='(')
- {
-
- if (cpt==0)
- {
- par[j]=i;
- j++;
- }
- cpt++;
- }
-
- if (chaine[i]==')')
- {
- cpt--;
- if (cpt==0)
- {
- par[j]=i;
- j++;
- }
- }
-
- }
- if(j%2!=0)
- {printf("il y a une erreur dans les parentheses.\n");return NULL;}
-
- if(chx[0]==1){printf("\t\t=================fait==============\n");}
-
- /** étape 2 définition des critaires d'arret de la récurtion . */
- if(chx[0]==1){printf("\t\t=================criteres d'arret de la recursion==============\n");}
- /** repere si il ne reste plus qu'un flotant */ //(la méthode n'est pas très elegante mais nous n'arrivons pas a utiliser strtof)
- char suite;
- suite='\0';
- int lect=0;
- lect=sscanf(chaine,"%f%c",&f1,&suite);
- if ((suite=='\0')&(lect>=1))
- {
- sscanf(chaine,"%f",&f1);
- printf("c'est un flotant flotant:%f\n\n",f1);
- root->val=f1;
- return root;
- }
- /** */
- if(chx[1]==1){printf("\t\t== c'est pas un flotant==\n");}
-
-
-
- /** repere si il ne reste plus qu'une fonction */
- //printf("strlen(chaine)%d par[1]+1=%d isalpha(chaine[0])=%d isalpha(chaine[1])=%d \n",strlen(chaine),par[1]+1,isalpha(chaine[0]),isalpha(chaine[1]));
- i=1;
- if ((j==2)&(strlen(chaine)== par[1]+1)&(isalpha(chaine[0])>0)&(isalpha(chaine[1])>0)) //si il n'y a plus qu'e 2 parentheses externes et qu'elles se terminent a la fin de la chaine.
- {
- //printf(" chaine+3 :%s",chaine+3);
- switch (chaine[1])
- {
- case'i': //sinus
- strcpy(root->fct,"sin");
- root->filsG= arbre(chaine+3,root);
- break;
- case 'o': //cosinus
- strcpy(root->fct,"cos");
- root->filsG= arbre(chaine+3,root);
- break;
- case 'a': //tan
- strcpy(root->fct,"tan");
- root->filsG= arbre(chaine+3,root);
- break;
-
-
- case 's': //arcsinus
- strcpy(root->fct,"asin");
- root->filsG= arbre(chaine+4,root);
- break;
- case 'c': //acosinus
- strcpy(root->fct,"cos");
- root->filsG= arbre(chaine+4,root);
- break;
- case 't': //atan
- strcpy(root->fct,"tan");
- root->filsG= arbre(chaine+4,root);
- break;
-
- case 'x': //exp
- strcpy(root->fct,"exp");
- root->filsG= arbre(chaine+3,root);
- break;
-
- default:
- printf("default\n");
- }
- root->parent= parent;
- printf("la fonction est %s\n\n",root->fct);
- return root;
- }
- if(chx[1]==1){printf("\t\t== c'est pas une fonction connue==\n");}
- /** */
-
- /** repere si il ne reste plus qu'un parametre */
- char param='\0';
- sscanf(chaine,"%c",¶m);
- if ((param <'a')||(param>'z')){param='\0';}
- if ((chaine[1]=='\0')&(param != '\0'))
- {
- printf("\nle parametre est:%c (=%d);chaine[0]=%c\n\n",param,param,chaine[0]);
- root->sVal=chaine[0];
- return root;
- }
- if(chx[1]==1){printf("\t\t== c'est pas un parametre==\n");}
- /** */
-
-
- /** repere si il ne reste plus qu'une chaine avec un exposant. Dans un premier temps l'exposant devras etre un flotant, pourras etre élargis a un parametre *
- // pour cette version un format est a respecter pour que l'exposant sois bien lu: si c'est un flotatn il faut le mettre entre parentheses.le flotant après lui sans parentheses.
- printf("expo\n");
- float exp;
- for(i=0;i maxP ;i++ )
- {
- if ((chaine[(par[i]+1)]=='^')&(j==2))
- {
- sscanf(chaine+par[1]+1,"%f",&exp);
- root-exposant=exp;
- }
- printf("f-expo");
- }
- printf("f-expo\n");
- printf("\t\t== c'est pas unun exposant==\n");
- ** */
-
- if(chx[1]==1){printf("\t\t== en fait il n'y a pas lieux de s'arreter==\n");}
- if(chx[0]==1){printf("\t\t== fait==\n");}
-
- /** étape 3 décomposition de la chaine autour du signe du noeud */
- /** on trouve le signe a mettre dans le noeud: c'est le signe le moins prioritaire dans le calcul */
- if(chx[0]==1){printf("\t\t============on trouve le signe a mettre dans le noeud===============\n");}
- int iS=0;
- int k=0;
- char signe[3];
-
-
- for (i=0;chaine[i]!='\0';i++)
- {
- if(i== par[k])
- {
- //printf("(...)");
- i=par[k+1]+1;
- k+=2;
- }/** on ne regarde pas ce qu'il y a dans les parentheses. **/
- //printf("%c",chaine[i]);
- if ((chaine[i]=='+')&(iS==0))
- {
- iS=i;
- signe[0]=chaine[i];
- }
-
- }
-
-
- if(chx[1]==1){printf("\t\t============si iS=0 il n'y a pas de signe '+'ou'-' (iS=%d) ===============\n",iS);}
- for (i=0;chaine[i]!='\0';i++)
- {
- if((i== par[k])&(par[k]!=par[k+1]))
- {
- // printf("(...)");
- i=par[k+1]+1;
- k+=2;
- }/** on ne regarde pas ce qu'il y a dans les parentheses. **/
- // printf("%c",chaine[i]);
- if (((chaine[i]=='*')||(chaine[i]=='/'))&(iS==0))
- {
- iS=i;
- signe[0]=chaine[i];
- }
-
- }
-
-
- if(chx[0]==1){printf("\t\t============fait===============\n");}
-
-
-
-
-
-
-
- /** test */
- if(iS==0){printf("\nerrrrrooooooooooooorrrrrrrrrrrrrrrrrrrr\n");}
- /** test */
-
-
- /** on coupe notre chaine en 2 autour du signe et on applique la récurtion */
- if(chx[0]==1){printf("\t\t=====on coupe la chaine en 2, a droite et a gauche du signe et on aplique la recurtion======\n");}
- chaineD=(chaine+iS+1);
- strncpy(chaineG,chaine,strlen(chaine)-strlen(chaineD)-1);
- chaineG[strlen(chaine)-strlen(chaineD)-1]='\0';
- /** ****************************/
- if(chx[2]==1){printf("chaineG:'%s'\n",chaineG);}
- if(chx[2]==1){printf("noeud:%c\n",signe[0]);}
- if(chx[2]==1){printf("chaineD:'%s'\n\n",chaineD);}
- /** ****************************/
- root->node= signe[0];
- root->filsG=arbre(chaineG,root);
- root->filsD=arbre(chaineD,root);
- root->parent= parent;
- if(chx[1]==1){printf("\t\t=====fait on retourne la racine======\n");}
- return root;
- }
-
- void afficher_arbre ( noeud *root)
- {
-
- if (root->filsG==NULL && root->filsD==NULL){
- if(root->val==0)
- {
- printf("%c",root->sVal);
- }
- else
- {
- printf("%f",root->val); // seul les noeuds sans fils ont des valeures en flotant
- }
- }
- else if ((root->filsG!=NULL)&(root->filsD!=NULL))
- {// si le fils gauche n'est pas NULL il n'as pas de valeur, et a apriori un filsG et un filsD
-
- printf("(");
- afficher_arbre ( root->filsG );
-
- printf("%c",root->node);
-
- afficher_arbre ( root->filsD );
- printf(")");
- }
-
- else if ((root->filsG!=NULL)&(root->filsD==NULL))// on est dans le cas d'une fonction;
- {
- printf("%s(",root->fct);
- afficher_arbre( root->filsG );
- printf(")");
- }
-
- else if (root ==NULL){ printf("haaaaaaaaa");}//si il n'y a pas de fils droit il me semble que c'est impossible, mais dans le doute..
- else {printf("errorrrrrre");} // tous les autres cas.
- }
-
-
-
- double tabascii[127]={0};// déclaré en globale pour memoriser les parametres
-
-
- double calculer( noeud *root)
- {
- if(chx[3]==1){printf("\n le parametre sVal :%c\n",root->sVal);}
- if((root->sVal >= 'a')&( root->sVal <= 'z'))
- {
- if (tabascii[root->sVal]==0)
- {
- printf("\nentrez une valeur pour le parametre :%c\n",root->sVal);
- scanf("%lf",&tabascii[root->sVal]);
- return tabascii[(root->sVal)];
- }
- else
- {
- return tabascii[(root->sVal)];
- }
- }
- if(root->fct!='\0')
- {
- switch (root->fct[1])
- {
- case 'i':
- return sin(calculer(root->filsG));
- case 'o':
- return cos(calculer(root->filsG));
- case 'a':
- return tan(calculer(root->filsG));
- case 't':
- return atan(calculer(root->filsG));
- case 's':
- return asin(calculer(root->filsG));
- case 'c':
- return acos(calculer(root->filsG));
- case 'x':
- return exp(calculer(root->filsG));
- }
-
- }
-
- if (root->val!=0.)
- return root->val;
-
- else
- switch (root->node)
- {
-
- case '+':
- return calculer(root->filsG) + calculer(root->filsD);
- break;
- case '-':
- return calculer(root->filsG) - calculer(root->filsD);
- break;
- case '*':
- return calculer(root->filsG) * calculer(root->filsD);
- break;
- case '/':
- return calculer(root->filsG) / calculer(root->filsD);
- break;
- default:
-
- printf("\nerreur opérateur de calcul inconu\nun signe ecris deux fois? ");
- //printf("\n le parametre sVal :%c\n",root->sVal);
- return 0.;
-
-
- }
- return 0;
- }
-
-
-
-
- void ajouter_lettre(char * chaine, char lettre)
- {
- char temp[2048];
- strcpy(temp, chaine);
- chaine[0]=lettre;
- strcpy(chaine+1,temp);
-
- }
-
-
-
-
- void signe_implicite(char * chaine) // corrige les '*' implicites devant les parentheses et remplace -5 par +-5 et 5-(123+4) par 5+-1*(123+4)
- {
- int i=0;
- for (i=0; chaine[i]!='\0';i++)
- {
- if(chaine[i+1]=='(')
- {
- if ((chaine[i]!='+')&(chaine[i]!='-')&(chaine[i]!='*')&(chaine[i]!='/'))
- {
- if(isalpha(chaine[i-1])&isalpha(chaine[i-2]))
- {}
- else
- {
- ajouter_lettre(chaine+i+1,'*');
- }
- }
-
- if ((chaine[i]=='-')& (((chaine[i-1]!='+')&(chaine[i-1]!='*')&(chaine[i-1]!='/'))||(i==0)))
- {
- if (i==0)
- {
- printf("la chaine est :%s\n",chaine);
- ajouter_lettre(chaine+i+1,'*');
- ajouter_lettre(chaine+i+1,'1');
-
- }
- else
- {
- printf("la chaine est :%s\n",chaine);
- scanf("%*c");
- ajouter_lettre(chaine+i,'+');
- ajouter_lettre(chaine+i+2,'*');
- ajouter_lettre(chaine+i+2,'1');
- }
- }
- }
-
- if ((chaine[i]=='-')&(isdigit(chaine[i+1])>0)&(i>0)& ((chaine[i-1]!='+')&(chaine[i-1]!='*')&(chaine[i-1]!='/')))
- {
- ajouter_lettre(chaine+i,'+');
- i++;
- }
-
- }
- }
-
-
-
-
-
-
- char * enleveParenthese(char *chaine)// cette fonction est recursive et permet d'enlever plusieurs parentheses inutiles,dont sont si friand ces etres humains, sans erreur.
- {
- int i;
-
- int cpt=0, par[maxP],j=0; //dans le tableau par on met les addresses (dans la chaine "chaine",as les pointeurs) des premieres parentheses externes
-
- for (i=0;(chaine[i]!='\0');i++)
- {
- if (chaine[i]=='(')
- {
-
- if (cpt==0)
- {
- par[j]=i;
- j++;
- }
- cpt++;
- }
-
- if (chaine[i]==')')
- {
- cpt--;
- if (cpt==0)
- {
- par[j]=i;
- j++;
- }
- }
-
- }
- if(j%2!=0)
- {printf("il y a une erreur dans les parentheses.\n");return NULL;}
-
- if ((j==2)&(chaine[0]=='(')&(chaine[strlen(chaine)-1]==')')) // si il n'y a que 2 parentheses , sont elles aux extrémitées?, si oui, on les enleve.
- {
- chaine++;
- chaine[strlen(chaine)-1]='\0';
- j+=-2;
- if(chx[2]==1){printf("chaine sans parentheses : %s \n",chaine);}
- return enleveParenthese(chaine);
- }
-
- return chaine;
-
- }
-
-
- void repere_fonctions(char * chaine) // met des parentheses au tour des fonctions definies et des parametres
- {
- int i,k;
-
- for (i=0;chaine[i]!='\0';i++)
- {
- if (isalpha(chaine[i])>0)
- {
- //printf("chaine[i+1]=%c i=%d chaine[i-1]=%c\n ",chaine[i+1],i,chaine[i-1]);
- switch (chaine[i])
- {
- case 'a'://soit on a affaire au parametre "a" soit c'est a la fonction asin ou acos ....
- if(((chaine[i+1]=='s')||(chaine[i+1]=='c')||(chaine[i+1]=='t'))&(par(chaine+i+4)+1!=')'))//pour alleger le code on estime que la probabilitée que ca ne sois pas un arcsinus ,arcosinus et arctangente est faible.
- {
- if ((chaine[i-1]!='(')||(i==0))
- {
- ajouter_lettre(chaine+i,'(');
- k=par(chaine+i+4);
- ajouter_lettre(chaine+i+k+4,')');
- i+=4;
- }
- else
- {
- i+=4;
- }
- }
- else if(((chaine[i-1]!='(')||(i==0))&(chaine[i+1]!=')'))
- {
- ajouter_lettre(chaine+i,'(');
- ajouter_lettre(chaine+i+2,')');
- }
- break;
-
-
- case 'c':
- if((chaine[i+1]=='o'))//pour alleger le code on estime que la probabilitée que ca ne sois pas un cosinus est faible.
- {
- if((chaine[i-1]!='(')||(i==0))
- {
- ajouter_lettre(chaine+i,'(');
- k=par(chaine+i+3);
- ajouter_lettre(chaine+i+k+3,')');
- i+=4;
- }
- else
- i+=4;
- }
- else if(((chaine[i-1]!='(')||(i==0))&(chaine[i+1]!=')'))
- {
- ajouter_lettre(chaine+i,'(');
- ajouter_lettre(chaine+i+2,')');
- }
- break;
-
-
-
-
- case 's':
- printf("\navant, la chaine sinus est :%s chaine[i-1]:%c\n",chaine,chaine[i-1]);
- if((chaine[i+1]=='i'))//pour alleger le code on estime que la probabilitée que ca ne sois pas un sinus est faible.
- {
- if((chaine[i-1]!='(')||(i==0))
- {
- ajouter_lettre(chaine+i,'(');
- k=par(chaine+i+3);
- ajouter_lettre(chaine+i+k+3,')');
- i+=4;
- }
- else
- i+=4;
-
- }
- else if(((chaine[i-1]!='(')||(i==0))&(chaine[i+1]!=')')&(chaine[i+1]!='i'))
- {
- ajouter_lettre(chaine+i,'(');
- ajouter_lettre(chaine+i+2,')');
- }
- break;
-
-
-
-
- case 't':
- if((chaine[i+1]=='a'))//pour alleger le code on estime que la probabilitée que ca ne sois pas un cosinus est faible.
- {
- if ((chaine[i-1]!='(')||(i==0))
- {
- ajouter_lettre(chaine+i,'(');
- k=par(chaine+i+3);
- ajouter_lettre(chaine+i+k+3,')');
- i+=4;
- }
- else
- i+=4;
- }
- else if(((chaine[i-1]!='(')||(i==0))&(chaine[i+1]!=')'))
- {
- ajouter_lettre(chaine+i,'(');
- ajouter_lettre(chaine+i+2,')');
- }
- break;
-
-
-
- case 'e':
- if(chaine[i+1]=='x')//pour alleger le code on estime que la probabilitée que ca ne sois pas un cosinus est faible.
- {
- if((chaine[i-1]!='(')||(i==0))
- {
- ajouter_lettre(chaine+i,'(');
- k=par(chaine+i+3);
- ajouter_lettre(chaine+i+k+3,')');
- i+=4;
- }
- else
- i+=4;
- }
- else if(((chaine[i-1]!='(')||(i==0))&(chaine[i+1]!=')'))
- {
- ajouter_lettre(chaine+i,'(');
- ajouter_lettre(chaine+i+2,')');
- }
- break;
-
-
- case 'b':case 'd':case 'f':case 'g':case 'h':case 'i':case 'j':case 'k':case 'l':case 'm':case 'n':case 'o':case 'p':case 'q':case 'r':case 'u':case 'v':case 'w':case 'x':case 'y':case 'z':
- if(((chaine[i-1]!='(')||(i==0))&(chaine[i+1]!=')'))
- {
- ajouter_lettre(chaine+i,'(');
- ajouter_lettre(chaine+i+2,')');
- }
- break;
- }
- }
- }
- }
-
- int par(char *chaine)//retourne l'indice dans la chaine de la parenthese qui ferme la premiere (toujours le premier caractere.)
- {
- int i,cpt=0;
- for (i=0;(chaine[i]!='\0');i++)
- {
- if (chaine[i]=='(')
- {
- cpt++;
- }
-
- if (chaine[i]==')')
- {
- cpt--;
- if (cpt==0)
- {
- return i;
- }
- }
- }
- return 0;
-
- }
-
-
-
-
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
#include<math.h>
#define _XOPEN_SOURCE 600 /* or #define _ISOC99_SOURCE */
#define maxP 1024 //maximum de parentheses externes d'un calcul.
#define MAX 2048
#define MAXarg 1024
typedef struct noeud {
char node;
char fct[4]; // pour pouvoir distinguer facilement les fonctions, comme sinus, des signes.
struct noeud * parent;
struct noeud * filsG;
struct noeud * filsD;
double val;
char sVal;
float exposant;
} noeud;
noeud * arbre(char *chaine, noeud * parent);
void afficher_arbre ( noeud * root);
double calculer( noeud *root);
void ajouter_lettre(char * chaine, char lettre); //décale la chaine et ajoute la lettre au debut.
void repere_fonctions(char * chaine);
int par(char*chaine);//retourne l'indice dans la chaine de la parenthese qui ferme la premiere (toujours le premier caractere.)
void signe_implicite(char * chaine); // corrige les '*' implicites devant les parentheses
char * enleveParenthese(char *chaine);
/** ***********************//** ***********************//** *********//** ***********************/
noeud * creerNoeud(noeud * parents)
{
noeud * nNoeud=malloc(sizeof(noeud));
nNoeud->filsD=NULL;
nNoeud->filsG=NULL;
nNoeud->val=0;
nNoeud->node='\0';
nNoeud->sVal='\0';
//nNoeud->fct[0]='\0';
//printf("noeud cree.\n");
nNoeud->parent=parents;
if(parents!=NULL)
{
if(parents->filsG!=NULL)
{
if(parents->filsD!=NULL)
{
printf("NULL Il y a un noeud qui est fiere de sa virilite... il voudrais un troisieme fils :D \n");
return NULL;
}
parents->filsD=nNoeud;
//printf("noeudD cree.\n");
return nNoeud;
}
parents->filsG=nNoeud;
//printf("noeudG cree.\n");
return nNoeud;
}
else
//printf("root cree.\n");
return nNoeud;
}
/** ***********************//** ***********************//** ***********************//** ***********************//** ***********************//** ***********************/
int chx[MAXarg]={0};
int main(){
chx[0]=0;chx[2]=1;/*
printf("choisisez l'affichage(mettre 1 pour oui( 0 pour on) dans l'ordre):\n\t'0'=>commentaires\n\t'1'=>commentaires complementaire\n\t'2'=>utile pour le debogage(conseille)\n\t'3'=>pour le debogage le reste en vrac (deconseille :D)" );
scanf("%d%d%d%d",&chx[0],&chx[1],&chx[2],&chx[3]);*/
noeud * root=NULL;
char chaine[MAX];
//chaine=malloc(sizeof(chaine)+1);
printf("coucou, entre ton calcul.\n");
scanf("%s",chaine);
root=arbre(chaine,root);
printf("afficher arbre:\n");
afficher_arbre (root);
printf("\nle resultat est %f\n",calculer(root));
printf("\n");
return 0;
}
noeud * arbre(char *chaine,noeud *parent){
char *chaineG;
char *chaineD;
noeud * root;
float f1=0;
root = creerNoeud(parent);
int i;
printf("la chaine est :%s\n",chaine);
if(chx[0]==1){printf("\t\t=======initialisation=========");}
chaine=enleveParenthese(chaine);
repere_fonctions(chaine); // met des parentheses au tour des fonctions definies et des parametres
signe_implicite(chaine); // corrige les '*' implicites devant les parentheses
if(chx[2]==1){ printf("chaine avec tous les signes et les parentheses en extra:%s\n",chaine);}
chaine=enleveParenthese(chaine); // protege des cas type (((1+2)))
if(chx[3]==1){ printf("chaine les parentheses aux extremitees:%s\n",chaine);}
/** décomposer la chaine en "S1 signe S2 " */
/** étape 1 : mise en boite des parentheses.*/
if(chx[0]==1){printf("\t\t=================mise en boite des parentheses==============\n");}
int cpt=0, par[maxP],j=0; //dans le tableau par on met les addresses (dans la chaine "chaine",as les pointeurs) des premieres parentheses externes
for (i=0;(chaine[i]!='\0');i++)
{
if (chaine[i]=='(')
{
if (cpt==0)
{
par[j]=i;
j++;
}
cpt++;
}
if (chaine[i]==')')
{
cpt--;
if (cpt==0)
{
par[j]=i;
j++;
}
}
}
if(j%2!=0)
{printf("il y a une erreur dans les parentheses.\n");return NULL;}
if(chx[0]==1){printf("\t\t=================fait==============\n");}
/** étape 2 définition des critaires d'arret de la récurtion . */
if(chx[0]==1){printf("\t\t=================criteres d'arret de la recursion==============\n");}
/** repere si il ne reste plus qu'un flotant */ //(la méthode n'est pas très elegante mais nous n'arrivons pas a utiliser strtof)
char suite;
suite='\0';
int lect=0;
lect=sscanf(chaine,"%f%c",&f1,&suite);
if ((suite=='\0')&(lect>=1))
{
sscanf(chaine,"%f",&f1);
printf("c'est un flotant flotant:%f\n\n",f1);
root->val=f1;
return root;
}
/** */
if(chx[1]==1){printf("\t\t== c'est pas un flotant==\n");}
/** repere si il ne reste plus qu'une fonction */
//printf("strlen(chaine)%d par[1]+1=%d isalpha(chaine[0])=%d isalpha(chaine[1])=%d \n",strlen(chaine),par[1]+1,isalpha(chaine[0]),isalpha(chaine[1]));
i=1;
if ((j==2)&(strlen(chaine)== par[1]+1)&(isalpha(chaine[0])>0)&(isalpha(chaine[1])>0)) //si il n'y a plus qu'e 2 parentheses externes et qu'elles se terminent a la fin de la chaine.
{
//printf(" chaine+3 :%s",chaine+3);
switch (chaine[1])
{
case'i': //sinus
strcpy(root->fct,"sin");
root->filsG= arbre(chaine+3,root);
break;
case 'o': //cosinus
strcpy(root->fct,"cos");
root->filsG= arbre(chaine+3,root);
break;
case 'a': //tan
strcpy(root->fct,"tan");
root->filsG= arbre(chaine+3,root);
break;
case 's': //arcsinus
strcpy(root->fct,"asin");
root->filsG= arbre(chaine+4,root);
break;
case 'c': //acosinus
strcpy(root->fct,"cos");
root->filsG= arbre(chaine+4,root);
break;
case 't': //atan
strcpy(root->fct,"tan");
root->filsG= arbre(chaine+4,root);
break;
case 'x': //exp
strcpy(root->fct,"exp");
root->filsG= arbre(chaine+3,root);
break;
default:
printf("default\n");
}
root->parent= parent;
printf("la fonction est %s\n\n",root->fct);
return root;
}
if(chx[1]==1){printf("\t\t== c'est pas une fonction connue==\n");}
/** */
/** repere si il ne reste plus qu'un parametre */
char param='\0';
sscanf(chaine,"%c",¶m);
if ((param <'a')||(param>'z')){param='\0';}
if ((chaine[1]=='\0')&(param != '\0'))
{
printf("\nle parametre est:%c (=%d);chaine[0]=%c\n\n",param,param,chaine[0]);
root->sVal=chaine[0];
return root;
}
if(chx[1]==1){printf("\t\t== c'est pas un parametre==\n");}
/** */
/** repere si il ne reste plus qu'une chaine avec un exposant. Dans un premier temps l'exposant devras etre un flotant, pourras etre élargis a un parametre *
// pour cette version un format est a respecter pour que l'exposant sois bien lu: si c'est un flotatn il faut le mettre entre parentheses.le flotant après lui sans parentheses.
printf("expo\n");
float exp;
for(i=0;i maxP ;i++ )
{
if ((chaine[(par[i]+1)]=='^')&(j==2))
{
sscanf(chaine+par[1]+1,"%f",&exp);
root-exposant=exp;
}
printf("f-expo");
}
printf("f-expo\n");
printf("\t\t== c'est pas unun exposant==\n");
** */
if(chx[1]==1){printf("\t\t== en fait il n'y a pas lieux de s'arreter==\n");}
if(chx[0]==1){printf("\t\t== fait==\n");}
/** étape 3 décomposition de la chaine autour du signe du noeud */
/** on trouve le signe a mettre dans le noeud: c'est le signe le moins prioritaire dans le calcul */
if(chx[0]==1){printf("\t\t============on trouve le signe a mettre dans le noeud===============\n");}
int iS=0;
int k=0;
char signe[3];
for (i=0;chaine[i]!='\0';i++)
{
if(i== par[k])
{
//printf("(...)");
i=par[k+1]+1;
k+=2;
}/** on ne regarde pas ce qu'il y a dans les parentheses. **/
//printf("%c",chaine[i]);
if ((chaine[i]=='+')&(iS==0))
{
iS=i;
signe[0]=chaine[i];
}
}
if(chx[1]==1){printf("\t\t============si iS=0 il n'y a pas de signe '+'ou'-' (iS=%d) ===============\n",iS);}
for (i=0;chaine[i]!='\0';i++)
{
if((i== par[k])&(par[k]!=par[k+1]))
{
// printf("(...)");
i=par[k+1]+1;
k+=2;
}/** on ne regarde pas ce qu'il y a dans les parentheses. **/
// printf("%c",chaine[i]);
if (((chaine[i]=='*')||(chaine[i]=='/'))&(iS==0))
{
iS=i;
signe[0]=chaine[i];
}
}
if(chx[0]==1){printf("\t\t============fait===============\n");}
/** test */
if(iS==0){printf("\nerrrrrooooooooooooorrrrrrrrrrrrrrrrrrrr\n");}
/** test */
/** on coupe notre chaine en 2 autour du signe et on applique la récurtion */
if(chx[0]==1){printf("\t\t=====on coupe la chaine en 2, a droite et a gauche du signe et on aplique la recurtion======\n");}
chaineD=(chaine+iS+1);
strncpy(chaineG,chaine,strlen(chaine)-strlen(chaineD)-1);
chaineG[strlen(chaine)-strlen(chaineD)-1]='\0';
/** ****************************/
if(chx[2]==1){printf("chaineG:'%s'\n",chaineG);}
if(chx[2]==1){printf("noeud:%c\n",signe[0]);}
if(chx[2]==1){printf("chaineD:'%s'\n\n",chaineD);}
/** ****************************/
root->node= signe[0];
root->filsG=arbre(chaineG,root);
root->filsD=arbre(chaineD,root);
root->parent= parent;
if(chx[1]==1){printf("\t\t=====fait on retourne la racine======\n");}
return root;
}
void afficher_arbre ( noeud *root)
{
if (root->filsG==NULL && root->filsD==NULL){
if(root->val==0)
{
printf("%c",root->sVal);
}
else
{
printf("%f",root->val); // seul les noeuds sans fils ont des valeures en flotant
}
}
else if ((root->filsG!=NULL)&(root->filsD!=NULL))
{// si le fils gauche n'est pas NULL il n'as pas de valeur, et a apriori un filsG et un filsD
printf("(");
afficher_arbre ( root->filsG );
printf("%c",root->node);
afficher_arbre ( root->filsD );
printf(")");
}
else if ((root->filsG!=NULL)&(root->filsD==NULL))// on est dans le cas d'une fonction;
{
printf("%s(",root->fct);
afficher_arbre( root->filsG );
printf(")");
}
else if (root ==NULL){ printf("haaaaaaaaa");}//si il n'y a pas de fils droit il me semble que c'est impossible, mais dans le doute..
else {printf("errorrrrrre");} // tous les autres cas.
}
double tabascii[127]={0};// déclaré en globale pour memoriser les parametres
double calculer( noeud *root)
{
if(chx[3]==1){printf("\n le parametre sVal :%c\n",root->sVal);}
if((root->sVal >= 'a')&( root->sVal <= 'z'))
{
if (tabascii[root->sVal]==0)
{
printf("\nentrez une valeur pour le parametre :%c\n",root->sVal);
scanf("%lf",&tabascii[root->sVal]);
return tabascii[(root->sVal)];
}
else
{
return tabascii[(root->sVal)];
}
}
if(root->fct!='\0')
{
switch (root->fct[1])
{
case 'i':
return sin(calculer(root->filsG));
case 'o':
return cos(calculer(root->filsG));
case 'a':
return tan(calculer(root->filsG));
case 't':
return atan(calculer(root->filsG));
case 's':
return asin(calculer(root->filsG));
case 'c':
return acos(calculer(root->filsG));
case 'x':
return exp(calculer(root->filsG));
}
}
if (root->val!=0.)
return root->val;
else
switch (root->node)
{
case '+':
return calculer(root->filsG) + calculer(root->filsD);
break;
case '-':
return calculer(root->filsG) - calculer(root->filsD);
break;
case '*':
return calculer(root->filsG) * calculer(root->filsD);
break;
case '/':
return calculer(root->filsG) / calculer(root->filsD);
break;
default:
printf("\nerreur opérateur de calcul inconu\nun signe ecris deux fois? ");
//printf("\n le parametre sVal :%c\n",root->sVal);
return 0.;
}
return 0;
}
void ajouter_lettre(char * chaine, char lettre)
{
char temp[2048];
strcpy(temp, chaine);
chaine[0]=lettre;
strcpy(chaine+1,temp);
}
void signe_implicite(char * chaine) // corrige les '*' implicites devant les parentheses et remplace -5 par +-5 et 5-(123+4) par 5+-1*(123+4)
{
int i=0;
for (i=0; chaine[i]!='\0';i++)
{
if(chaine[i+1]=='(')
{
if ((chaine[i]!='+')&(chaine[i]!='-')&(chaine[i]!='*')&(chaine[i]!='/'))
{
if(isalpha(chaine[i-1])&isalpha(chaine[i-2]))
{}
else
{
ajouter_lettre(chaine+i+1,'*');
}
}
if ((chaine[i]=='-')& (((chaine[i-1]!='+')&(chaine[i-1]!='*')&(chaine[i-1]!='/'))||(i==0)))
{
if (i==0)
{
printf("la chaine est :%s\n",chaine);
ajouter_lettre(chaine+i+1,'*');
ajouter_lettre(chaine+i+1,'1');
}
else
{
printf("la chaine est :%s\n",chaine);
scanf("%*c");
ajouter_lettre(chaine+i,'+');
ajouter_lettre(chaine+i+2,'*');
ajouter_lettre(chaine+i+2,'1');
}
}
}
if ((chaine[i]=='-')&(isdigit(chaine[i+1])>0)&(i>0)& ((chaine[i-1]!='+')&(chaine[i-1]!='*')&(chaine[i-1]!='/')))
{
ajouter_lettre(chaine+i,'+');
i++;
}
}
}
char * enleveParenthese(char *chaine)// cette fonction est recursive et permet d'enlever plusieurs parentheses inutiles,dont sont si friand ces etres humains, sans erreur.
{
int i;
int cpt=0, par[maxP],j=0; //dans le tableau par on met les addresses (dans la chaine "chaine",as les pointeurs) des premieres parentheses externes
for (i=0;(chaine[i]!='\0');i++)
{
if (chaine[i]=='(')
{
if (cpt==0)
{
par[j]=i;
j++;
}
cpt++;
}
if (chaine[i]==')')
{
cpt--;
if (cpt==0)
{
par[j]=i;
j++;
}
}
}
if(j%2!=0)
{printf("il y a une erreur dans les parentheses.\n");return NULL;}
if ((j==2)&(chaine[0]=='(')&(chaine[strlen(chaine)-1]==')')) // si il n'y a que 2 parentheses , sont elles aux extrémitées?, si oui, on les enleve.
{
chaine++;
chaine[strlen(chaine)-1]='\0';
j+=-2;
if(chx[2]==1){printf("chaine sans parentheses : %s \n",chaine);}
return enleveParenthese(chaine);
}
return chaine;
}
void repere_fonctions(char * chaine) // met des parentheses au tour des fonctions definies et des parametres
{
int i,k;
for (i=0;chaine[i]!='\0';i++)
{
if (isalpha(chaine[i])>0)
{
//printf("chaine[i+1]=%c i=%d chaine[i-1]=%c\n ",chaine[i+1],i,chaine[i-1]);
switch (chaine[i])
{
case 'a'://soit on a affaire au parametre "a" soit c'est a la fonction asin ou acos ....
if(((chaine[i+1]=='s')||(chaine[i+1]=='c')||(chaine[i+1]=='t'))&(par(chaine+i+4)+1!=')'))//pour alleger le code on estime que la probabilitée que ca ne sois pas un arcsinus ,arcosinus et arctangente est faible.
{
if ((chaine[i-1]!='(')||(i==0))
{
ajouter_lettre(chaine+i,'(');
k=par(chaine+i+4);
ajouter_lettre(chaine+i+k+4,')');
i+=4;
}
else
{
i+=4;
}
}
else if(((chaine[i-1]!='(')||(i==0))&(chaine[i+1]!=')'))
{
ajouter_lettre(chaine+i,'(');
ajouter_lettre(chaine+i+2,')');
}
break;
case 'c':
if((chaine[i+1]=='o'))//pour alleger le code on estime que la probabilitée que ca ne sois pas un cosinus est faible.
{
if((chaine[i-1]!='(')||(i==0))
{
ajouter_lettre(chaine+i,'(');
k=par(chaine+i+3);
ajouter_lettre(chaine+i+k+3,')');
i+=4;
}
else
i+=4;
}
else if(((chaine[i-1]!='(')||(i==0))&(chaine[i+1]!=')'))
{
ajouter_lettre(chaine+i,'(');
ajouter_lettre(chaine+i+2,')');
}
break;
case 's':
printf("\navant, la chaine sinus est :%s chaine[i-1]:%c\n",chaine,chaine[i-1]);
if((chaine[i+1]=='i'))//pour alleger le code on estime que la probabilitée que ca ne sois pas un sinus est faible.
{
if((chaine[i-1]!='(')||(i==0))
{
ajouter_lettre(chaine+i,'(');
k=par(chaine+i+3);
ajouter_lettre(chaine+i+k+3,')');
i+=4;
}
else
i+=4;
}
else if(((chaine[i-1]!='(')||(i==0))&(chaine[i+1]!=')')&(chaine[i+1]!='i'))
{
ajouter_lettre(chaine+i,'(');
ajouter_lettre(chaine+i+2,')');
}
break;
case 't':
if((chaine[i+1]=='a'))//pour alleger le code on estime que la probabilitée que ca ne sois pas un cosinus est faible.
{
if ((chaine[i-1]!='(')||(i==0))
{
ajouter_lettre(chaine+i,'(');
k=par(chaine+i+3);
ajouter_lettre(chaine+i+k+3,')');
i+=4;
}
else
i+=4;
}
else if(((chaine[i-1]!='(')||(i==0))&(chaine[i+1]!=')'))
{
ajouter_lettre(chaine+i,'(');
ajouter_lettre(chaine+i+2,')');
}
break;
case 'e':
if(chaine[i+1]=='x')//pour alleger le code on estime que la probabilitée que ca ne sois pas un cosinus est faible.
{
if((chaine[i-1]!='(')||(i==0))
{
ajouter_lettre(chaine+i,'(');
k=par(chaine+i+3);
ajouter_lettre(chaine+i+k+3,')');
i+=4;
}
else
i+=4;
}
else if(((chaine[i-1]!='(')||(i==0))&(chaine[i+1]!=')'))
{
ajouter_lettre(chaine+i,'(');
ajouter_lettre(chaine+i+2,')');
}
break;
case 'b':case 'd':case 'f':case 'g':case 'h':case 'i':case 'j':case 'k':case 'l':case 'm':case 'n':case 'o':case 'p':case 'q':case 'r':case 'u':case 'v':case 'w':case 'x':case 'y':case 'z':
if(((chaine[i-1]!='(')||(i==0))&(chaine[i+1]!=')'))
{
ajouter_lettre(chaine+i,'(');
ajouter_lettre(chaine+i+2,')');
}
break;
}
}
}
}
int par(char *chaine)//retourne l'indice dans la chaine de la parenthese qui ferme la premiere (toujours le premier caractere.)
{
int i,cpt=0;
for (i=0;(chaine[i]!='\0');i++)
{
if (chaine[i]=='(')
{
cpt++;
}
if (chaine[i]==')')
{
cpt--;
if (cpt==0)
{
return i;
}
}
}
return 0;
}
Conclusion
pour la compilation rajouter " -lm " pour la librairie math.h (^^ ça m'as pris deux jours pour le trouver )
la source ,développé et compilée avec gcc (knoppix), marche mais je n'arrive pas a la faire marcher avec devC++. je crois qu'il y a un problème avec les malloc et je devrais peut être rajouter une fonction qui free les noeuds de l'arbre.
développements futurs: -développer les expressions paramétrées -factoriser de toutes les façons possible ces expressions (via un calcul matriciel) -tracer dans X11
^^ ne soyez pas trop dur c'est mon premier petit programme.
Sources du même auteur
Sources de la même categorie
Commentaires et avis
Discussions en rapport avec ce code source dans le forum
créer un arbre à partir d'un fichier word [ par yeager ]
Bonjour je suis nouveau et débutant en langage CJe souhaite pouvoir lire un fichier word comportant des informations sur plusieurs livres. A partir de
Structures, pointeurs, malloc et realloc reunis !! :) [ par mindark ]
Alors la, je suis completement coulé !Voila mon probleme :J'ai une tableau "grid" qui est un tableau de structures "cell" :struct cell {bool bloquant;
pb avec les structures en C [ par james ]
j'aurai aimé savoir comment sont implementées les structures en C en memoire.On m'a dit qu'il y avait des zeros entre chaque type differents de la str
Construction d'un arbre à partir d'une chaine de caractères [ par dahlsimus ]
Bonjour, Je souhaite construire un arbre représentant une expression booléenne saisie sous le forme d'une chaîne de caractère (ex: (a+b).C avec + OR e
bleme avec les structures [ par djamine ]
j'ai un bleme j'aimerais que tu m'aide avec les structuresTAF:en utilisant un tableau de structure Je dois ecrire un programme qui saisi les noms et l
ecriture dans fichiers avec l'aide de structures [ par lucypher ]
Je cherche comment faire une fonction permettant d'ecrire, par l'intermediaire d'une structure, dans un fichier. Je cherche egalement (et c'est encore
trier et classer un tableau de structures [ par requinB ]
bonjour;mes amis, je bloque...sur comment trier et classer un tableau de structures...le tableau comprend un estructure article: code en int, libelle
tableau de structures type pointeur [ par chocho ]
Voila, je fait en c unpetit utilitaire de gestion d'adhérents.pour cela j'uilise un tableau de structure adhérent composée de deux pointeurs char *nom
[MFC] Utilisation de la classe CTreeCtrl, niveau dans l'arbre [ par karine3884 ]
Bonjour, Je programme sous Visual Studio C++ 6.0. J'utilise un CtreeCtrl pour créer un arbre (une arborescence). J'aimerai ajouter un item au même ni
Arbre de Huffman: y'a t-il qq1 pour me corriger?? [ par danje ]
Bonjour, Voilà, je viens de faire un arbre de Huffman suivant un tableau de fréquence de répétition de caractère. Mais je crois que mona rbre est faux
|
Derniers Blogs
IMAGINE CUP 2012, MAKE A SIGN EN FINALEIMAGINE CUP 2012, MAKE A SIGN EN FINALE par junarnoalg
Voilà qui est fait, la nouvelle est officielle ! L'équipe belge "Make a Sign" va au pays des kangourous défendre son projet dans la catégorie Software Design. http://www.imaginecup.com/CompetitionsContent/Competition/WorldwideFinalists.aspx V...
Cliquez pour lire la suite de l'article par junarnoalg KINECT 1.5 IS OUT !KINECT 1.5 IS OUT ! par Vko
La version 1.5 du Kinect For Microsoft vient tout juste de sortir ! Plein de nouveautés: Tracking de squelette en Near Mode Détection en position assise Détection faciale avec un SDK dédié Documentation et des guideline (enfin) Un out...
Cliquez pour lire la suite de l'article par Vko LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) par richardc
Mise à jour des Web API du 14 Mai
Réservez dès maintenant votre journée du 20 juin pour le Windows Azure Dev Camp 2012 à Paris
Mise à jour de Team Foundation Service
MechCommander 2 sur Windows 8
Entity Framework 5 Release Candidate e...
Cliquez pour lire la suite de l'article par richardc REACTIVE EXTENSIONS : CONSOMMER DES SERVICES AVEC RX PARTIE 3, LES PIèGES à éVITERREACTIVE EXTENSIONS : CONSOMMER DES SERVICES AVEC RX PARTIE 3, LES PIèGES à éVITER par Groc
Une mauvaise utilisation de rx lors de l'écriture d'une couche d'accès à des services peut conduire à des cas embarassants avec des erreurs mal gérées, des appels qui ne partent lorsqu'ils le devraient, et même des résultats incorrects . le tout nuis...
Cliquez pour lire la suite de l'article par Groc SHAREPOINT BLOG SITE, PROBLèME D'ARCHIVESSHAREPOINT BLOG SITE, PROBLèME D'ARCHIVES par junarnoalg
Dernièrement, nous avons migré le site
myTIC
vers un nouveau serveur SharePoint 2010. Dans les contenus que nous vouloins récupérer, nous avions un certain nombre de blogs.
Nous avons utilisé les commandes Power...
Cliquez pour lire la suite de l'article par junarnoalg
Forum
MATRICE TEMPLATEMATRICE TEMPLATE par hjr2610
Cliquez pour lire la suite par hjr2610 RE : SAC A DOS RE : SAC A DOS par hadjkaddour
Cliquez pour lire la suite par hadjkaddour
Logiciels
sDEVIS-FACTURES vlPRO (8.1.0.3)SDEVIS-FACTURES VLPRO (8.1.0.3)sDEVIS-FACTURES vlPRO a été mis au point pour les particuliers, créateurs, entrepreneurs, artisa... Cliquez pour télécharger sDEVIS-FACTURES vlPRO 974 Application Server (12.2.4.6)974 APPLICATION SERVER (12.2.4.6)Développez de puissantes applications dans un environnement de 'cloud computing', clusterisé, séc... Cliquez pour télécharger 974 Application Server vPicture (1.4.2.1)VPICTURE (1.4.2.1)Avec vPicture, hébergez vos images facilement et rapidement.
vPicture est un utilitaire simple, ... Cliquez pour télécharger vPicture Easy-Planning (2.2.1.6)EASY-PLANNING (2.2.1.6)Easy-Planning permet de créer des plannings sous la représentation de diagrammes et est adapté au... Cliquez pour télécharger Easy-Planning COM-BACKUP (2.0)COM-BACKUP (2.0)
COM-BACKUP est un logiciel de sauvegarde qui permet de planifier les sauvegardes de vos dossiers ...
Cliquez pour télécharger COM-BACKUP
|