Calculette scientifique [djgpp]

Description

Voici la source d'une fonction qui resoud un calcul en faisant les regles de priorites et de parentheses.
Normalement elle repere les fautes de syntaxe mais pas les calculs impossibles (0^0, 5/0, (-5)^0.5 ,...), mais vous pouvez aisement rajouter cela
C'est aussi mon premier programme qui utilise des listes chainees alors il y a sans doute des erreurs.

Source / Exemple :


#include						<math.h>	/* pour pow */
#include						<stdio.h>	/* pour printf et scanf */
#include						<stdlib.h>	/* pour malloc et free */

#define							MATH_OP_SPC				' '
#define							MATH_OP_PNT				'.'
#define							MATH_OP_ADD				'+'
#define							MATH_OP_SUB				'-'
#define							MATH_OP_MUL				'*'
#define							MATH_OP_DIV				'/'
#define							MATH_OP_MOD				'%'
#define							MATH_OP_POW				'^'
#define							MATH_OP_BRL				'('
#define							MATH_OP_BRR				')'

#define							MATH_isnumber(c)			(((c)<='9')&&((c)>='0'))
#define							MATH_isoperator(c)			(((c)==MATH_OP_ADD)||((c)==MATH_OP_POW)||\
												 ((c)==MATH_OP_SUB)||((c)==MATH_OP_MUL)||\
												 ((c)==MATH_OP_BRL)||((c)==MATH_OP_BRR)||\
												 ((c)==MATH_OP_DIV)||((c)==MATH_OP_MOD))

struct							MATH 
{
	double						val;
	char						op;
	struct MATH					*previous;
	struct MATH					*next;
};

////////////////////////////////////////////////////////////////////////////////////////

void							resolve_convert(char *str,struct MATH **calc)
{
	double						value;
	unsigned int					i;
	unsigned int					i2;

	/* ----------------------- */
	/* --- INITIALISATIONS --- */
	/* ----------------------- */

  • calc=(struct MATH*)(malloc(sizeof(struct MATH)));
(*calc)->previous=NULL; /* initialise la liste chainee */ (*calc)->next=NULL; /* initialise la liste chainee */ /* ------------------ */ /* --- CONVERSION --- */ /* ------------------ */ i=0; while (str[i]!=0) { /* -------------------- */ /* --- SI UN NOMBRE --- */ /* -------------------- */ if (MATH_isnumber(str[i])) { (*calc)->val=0; (*calc)->op=NULL; while (MATH_isnumber(str[i])) { (*calc)->val*=10; /* on multiplie par 10 */ (*calc)->val+=str[i++]-'0'; /* on rajoute le nombre */ } /* --- SI UNE VIRGULE --- */ if (str[i]==MATH_OP_PNT) { i++; i2=0; value=0; while (MATH_isnumber(str[i])) { value*=10; /* on multiplie par 10 */ value+=str[i++]-'0'; /* on rajoute le nombre */ i2++; } while (i2--) value/=10; /* on divise */ (*calc)->val+=value; /* et on rajoute au nombre */ } (*calc)->next=(struct MATH*)(malloc(sizeof(struct MATH))); (*calc)->next->previous=*calc;
  • calc=(*calc)->next;
(*calc)->next=NULL; continue; } /* ----------------------- */ /* --- SI UN OPERATEUR --- */ /* ----------------------- */ if (MATH_isoperator(str[i])) { (*calc)->op=str[i++]; (*calc)->next=(struct MATH*)(malloc(sizeof(struct MATH))); (*calc)->next->previous=*calc;
  • calc=(*calc)->next;
(*calc)->next=NULL; continue; } /* ------------------------------- */ /* --- SINON CARACTERE INCONNU --- */ /* ------------------------------- */ if (str[i]!=MATH_OP_SPC) { while ((*calc)->next!=NULL) *calc=(*calc)->next; while ((*calc)->previous!=NULL) {
  • calc=(*calc)->previous;
free((*calc)->next); } free(*calc);
  • calc=NULL;
return; } } /* ------------------- */ /* --- CORRECTIONS --- */ /* ------------------- */ /* --- TROP DE PARENTHESES --- */ while ((*calc)->previous!=NULL) *calc=(*calc)->previous; i=0; while ((*calc)->next!=NULL) { if ((*calc)->op==MATH_OP_BRL) i++; if ((*calc)->op==MATH_OP_BRR) i--;
  • calc=(*calc)->next;
}
  • calc=(*calc)->previous;
if ((i!=0)||(((*calc)->op!=MATH_OP_BRL)&&((*calc)->op!=MATH_OP_BRR)&&((*calc)->op!=NULL))) {
  • calc=(*calc)->next;
while ((*calc)->previous!=NULL) {
  • calc=(*calc)->previous;
free((*calc)->next); } free(*calc);
  • calc=NULL;
return; } while ((*calc)->previous!=NULL) *calc=(*calc)->previous; while ((*calc)->next!=NULL) { /* --- NOMBRES NEGATIFS ET POSITIFS --- */ if ((((*calc)->op==MATH_OP_ADD)||((*calc)->op==MATH_OP_SUB))&&(((*calc)->previous==NULL)||((*calc)->previous->op==MATH_OP_BRL))) { (*calc)->previous->next=(struct MATH*)(malloc(sizeof(struct MATH))); (*calc)->previous->next->op=NULL; (*calc)->previous->next->val=0; (*calc)->previous->next->previous=(*calc)->previous; (*calc)->previous->next->next=*calc; (*calc)->previous=(*calc)->previous->next; } /* --- NOMBRE DEVANT UNE PARENTHESE POUR LA MULTIPLICATION --- */ if (((*calc)->op==MATH_OP_BRL)&&((*calc)->previous->op==NULL)&&((*calc)->previous!=NULL)) { (*calc)->previous->next=(struct MATH*)(malloc(sizeof(struct MATH))); (*calc)->previous->next->op=MATH_OP_MUL; (*calc)->previous->next->previous=(*calc)->previous; (*calc)->previous->next->next=*calc; (*calc)->previous=(*calc)->previous->next; } /* --- ERREURS DE SYNTAXE : DEUX NOMBRES SE SUIVANT --- */ if (((*calc)->op==NULL)&&((*calc)->previous->op==NULL)&&((*calc)->previous!=NULL)) { while ((*calc)->next!=NULL) *calc=(*calc)->next; while ((*calc)->previous!=NULL) {
  • calc=(*calc)->previous;
free((*calc)->next); } free(*calc);
  • calc=NULL;
return; } /* --- ERREURS DE SYNTAXE : DEUX OPERATEURS SE SUIVANT (HORS PARENTHESES) --- */ if (((*calc)->op==(*calc)->previous->op)&&((*calc)->op!=MATH_OP_BRR)&&((*calc)->op!=MATH_OP_BRL) &&((*calc)->previous->op!=MATH_OP_BRR)&&((*calc)->previous->op!=MATH_OP_BRL)&&((*calc)->previous!=NULL)) { while ((*calc)->next!=NULL) *calc=(*calc)->next; while ((*calc)->previous!=NULL) {
  • calc=(*calc)->previous;
free((*calc)->next); } free(*calc);
  • calc=NULL;
return; }
  • calc=(*calc)->next; /* on avance d'un element */
} while ((*calc)->previous!=NULL) *calc=(*calc)->previous; /* --- SI OPERATEUR EN TETE DE CALCUL --- */ if (((*calc)->op!=MATH_OP_BRL)&&((*calc)->op!=MATH_OP_BRR)&&((*calc)->op!=NULL)) { while ((*calc)->next!=NULL) *calc=(*calc)->next; while ((*calc)->previous!=NULL) {
  • calc=(*calc)->previous;
free((*calc)->next); } free(*calc);
  • calc=NULL;
return; } } //////////////////////////////////////////////////////////////////////////////////////// void resolve_MATH(struct MATH **calc) { struct MATH *math=NULL; struct MATH *math2=NULL; struct MATH *math3=NULL; unsigned int i; unsigned int i2; /* ------------------- */ /* --- PARENTHESES --- */ /* ------------------- */ for (i=0 ; (*calc)->next!=NULL ; i++) { if ((*calc)->op==MATH_OP_BRL) { /* --- EFFACEMENT DE LA PARENTHESE D'OUVERTURE --- */ (*calc)->previous->next=(*calc)->next; /* on efface cette parenthese de la liste */ (*calc)->next->previous=(*calc)->previous; /* on efface cette parenthese de la liste */ math3=*calc; /* pour liberer la memoire */
  • calc=(*calc)->next; /* on avance d'un element */
free(math3); /* on libere la memoire */ math2=*calc; /* et on memorise l'adresse actuelle */ /* --- RECHERCHE DE LA PARENTHESE DE FERMETURE --- */ i2=1; /* contient le nombre de parenthese ouverte */ while (i2) /* on cherche la parenthese de fermeture */ { if ((*calc)->op==MATH_OP_BRL) i2++; /* augmente le compteur si encore une parenthese ouverte */ if ((*calc)->op==MATH_OP_BRR) i2--; /* si une parenthese de fermeture on le diminue */
  • calc=(*calc)->next; /* element suivant */
} /* des que i2==0 (plus de parenthese) on sort de la boucle */
  • calc=(*calc)->previous; /* on recule d'un element */
/* --- EFFACEMENT DE CETTE PARENTHESE --- */ (*calc)->previous->next=(*calc)->next; /* on efface cette parenthese de la liste */ (*calc)->next->previous=(*calc)->previous; /* on efface cette parenthese de la liste */ math3=*calc; /* pour liberer la memoire */
  • calc=(*calc)->previous; /* on recule d'un element */
free(math3); /* on libere la memoire */ math=(*calc)->next; /* et on retiens l'adresse de l'element suivant, c'est a dire celui apres la parenthese */ (*calc)->next=(struct MATH*)(malloc(sizeof(struct MATH))); /* car apres on cree un nouvel element */ (*calc)->next->previous=*calc; /* l'element precedent de l'element suivant est l'element actuel */
  • calc=(*calc)->next; /* on va a ce nouvel element */
(*calc)->next=NULL; /* et on le fait pointer sur NULL (fin de la liste) */ /* --- RESOLUTION DU CONTENU DE LA PARENTHESE --- */
  • calc=math2; /* d'abord on retourne au debut de la parenthese */
resolve_MATH(calc); /* puis on resoud */ (*calc)->next=math; /* on rattache le resultat et le reste de la liste */ (*calc)->next->previous=*calc; /* on rattache le resultat et le reste de la liste */ }
  • calc=(*calc)->next; /* element suivant */
} while (i--) *calc=(*calc)->previous; /* retour au debut de la liste */ /* ----------------- */ /* --- EXPOSANTS --- */ /* ----------------- */ math=*calc; /* on fais pointer math sur le calcul */ while (math->next!=NULL) { if (math->op==MATH_OP_POW) { math2=math; math3=math->next; math->previous->val=pow(math->previous->val,math->next->val); /* precedent ^ suivant */ math->previous->next=math->next->next; /* on elimine l'operande de la liste */ math->next->next->previous=math->previous; /* on elimine le nombre de la liste */ math=math->next->next; /* on avance de deux elements */ free(math2); /* on libere la memoire */ free(math3); /* on libere la memoire */ } else math=math->next; /* element suivant */ } /* --------------------------------------------- */ /* --- MULTIPLICATIONS, DIVISIONS ET MODULOS --- */ /* --------------------------------------------- */ math=*calc; /* on fais pointer math sur le calcul */ while (math->next!=NULL) { /* --- MULTIPLICATIONS --- */ if (math->op==MATH_OP_MUL) { math2=math; math3=math->next; math->previous->val*=math->next->val; /* precedent * suivant */ math->previous->next=math->next->next; /* on elimine l'operande de la liste */ math->next->next->previous=math->previous; /* on elimine le nombre de la liste */ math=math->next->next; /* on avance de deux elements */ free(math2); /* on libere la memoire */ free(math3); /* on libere la memoire */ } /* --- DIVISIONS --- */ else if (math->op==MATH_OP_DIV) { math2=math; math3=math->next; math->previous->val/=math->next->val; /* precedent / suivant */ math->previous->next=math->next->next; /* on elimine l'operande de la liste */ math->next->next->previous=math->previous; /* on elimine le nombre de la liste */ math=math->next->next; /* on avance de deux elements */ free(math2); /* on libere la memoire */ free(math3); /* on libere la memoire */ } /* --- MODULOS --- */ else if (math->op==MATH_OP_MOD) { math2=math; math3=math->next; math->previous->val=(long)(math->previous->val); /* nombres entiers uniquement */ math->next->val=(long)(math->next->val); /* nombres entiers uniquement */ (long)(math->previous->val)%=(long)(math->next->val); /* precedent % suivant */ math->previous->next=math->next->next; /* on elimine l'operande de la liste */ math->next->next->previous=math->previous; /* on elimine le nombre de la liste */ math=math->next->next; /* on avance de deux elements */ free(math2); /* on libere la memoire */ free(math3); /* on libere la memoire */ } else math=math->next; /* element suivant */ } /* ---------------------------------- */ /* --- ADDITIONS ET SOUSTRACTIONS --- */ /* ---------------------------------- */ math=*calc; /* on fais pointer math sur le calcul */ while (math->next!=NULL) { /* --- ADDITIONS --- */ if (math->op==MATH_OP_ADD) { math2=math; math3=math->next; math->previous->val+=math->next->val; /* precedent + suivant */ math->previous->next=math->next->next; /* on elimine l'operande de la liste */ math->next->next->previous=math->previous; /* on elimine le nombre de la liste */ math=math->next->next; /* on avance de deux elements */ free(math2); /* on libere la memoire */ free(math3); /* on libere la memoire */ } /* --- SOUSTRACTIONS --- */ else if (math->op==MATH_OP_SUB) { math2=math; math3=math->next; math->previous->val-=math->next->val; /* precedent - suivant */ math->previous->next=math->next->next; /* on elimine l'operande de la liste */ math->next->next->previous=math->previous; /* on elimine le nombre de la liste */ math=math->next->next; /* on avance de deux elements */ free(math2); /* on libere la memoire */ free(math3); /* on libere la memoire */ } else math=math->next; /* element suivant */ } free((*calc)->next); (*calc)->next=NULL; } //////////////////////////////////////////////////////////////////////////////////////// double resolve(char *str) { struct MATH *var; double val=0; resolve_convert(str,&var); if (var) { resolve_MATH(&var); val=var->val; free(var); } else printf("\nerror"); return val; } //////////////////////////////////////////////////////////////////////////////////////// int main() { char str[100]; scanf("%s",str); printf("\n%f",resolve(str)); return 0; }

Conclusion :


Voila ! Si vous trouvez des manieres d'optimiser le code tout en restant dans le C, n'hesitez pas a me le dire !

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.