Partage
  • Partager sur Facebook
  • Partager sur Twitter

zCalc

Du 1er au 30 Septembre

    31 août 2010 à 20:25:08

    Bonjour à tous,

    Ce topic vous permettra d'exposer vos solutions ou de poser vos questions en rapport avec l'exercice du mois de Septembre : zCalc.

    Bonne chance.
    • Partager sur Facebook
    • Partager sur Twitter
      31 août 2010 à 22:45:04

      Aller, histoire de lancer le truc. :)
      Je colle pas exactement à l'exo, mais je le ferai après. :)
      J'ai pas géré les parenthèses ni les erreurs de syntaxe, je considère l'utilisateur intelligent (comment ça j'ai tord ?). :-°

      #include <stdio.h>
      #include <stdlib.h>
      #include <ctype.h>
      #include <string.h>
      
      
      #define N_MAX 1000
      
      enum { VIDE, NUMER, OPER };
      
      typedef struct stack_s {
        int st[N_MAX][2];
        int i_st;
      } stack;
      
      
      #pragma mark Globales
      stack stack1;
      stack stack2;
      
      int isoper(int n) {
        char oper[] = { '+', '-', '*', '/' };
        int sz = sizeof oper / sizeof *oper;
        int i;
        
        for (i = 0; i < sz; i++)
          if (n == oper[i])
            return 1;
        return 0;
      }
      
      int set_prio(int op) {
        int i, sz;
        struct {
          char op;
          int val;
        } equ[] = {
          { '+', 1 },
          { '-', 2 },
          { '*', 3 },
          { '/', 4 }
        };
        
        sz = sizeof equ / sizeof *equ;
        for (i = 0; i < sz; i++)
          if (op == equ[i].op)
            return equ[i].val;
        
        /* Opérateur pas dans la liste */
        return 0;
      }
      
      /* Retourne la priorité de op1 par rapport à op2 */
      /* + < - < * < / */
      int priorite(int op1, int op2) {
        op1 = set_prio(op1);
        op2 = set_prio(op2);
        return op1 > op2;
      }
      
      void push_number(stack * s, int n) {
        s->st[s->i_st][0] = n;
        s->st[s->i_st][1] = NUMER;
        s->i_st++;
      }
      
      void push_op(stack * s, int op) {
        s->st[s->i_st][0] = op;
        s->st[s->i_st][1] = OPER;
        s->i_st++;
      }
      
      int pop(stack * s) {
        int tmp = s->st[s->i_st-1][0];
        s->st[s->i_st-1][0] = VIDE;
        s->st[s->i_st-1][1] = VIDE;
        s->i_st--;
        return tmp;
      }
      
      /* La stack 1 sert pour la NPI, la stack 2 pour les opérateurs */
      /* Une fois la fonction finie, seule la stack 1 est remplie */
      void convert_npi(char * s) {
        
        while (*s) {
          /* On vide les blancs */
          while (isspace(*s))
            s++;
          
          /* Si c'est un nombre */
          if (isdigit(*s)) {
            push_number(&stack1, strtol(s, &s, 10));
          }
          /* Si c'est un opérateur */
          else if (isoper(*s)) {
            /* On ajoute sur la stack 2 si elle est vide */
            if (stack2.i_st == 0) {
              push_op(&stack2, *s);
            }
            /* Sinon on regarde la priorité des opérateurs.
             * Si l'opérateur en cours a une prio plus importante, on le stocke,
             * sinon on depop sur la stack 1 */
            else {
              if (priorite(*s, stack2.st[stack2.i_st-1][0]) == 1) {
                push_op(&stack2, *s);
              }
              else {
                /* Tant que la prio de l'op en cours est inférieur à celle
                 * sur la stack, on dépile sur la stack 1 */
                while (priorite(*s, stack2.st[stack2.i_st-1][0]) != 1) {
                  int tmp = pop(&stack2);
                  push_op(&stack1, tmp);
                }
                /* On mets l'op sur la stack 2 */
                push_op(&stack2, *s);
              }
            }
            /* On passe l'opérateur */
            s++;
          }
        }
        
        /* Une fois que la chaîne est vide,
         * il faut vider la stack 2 sur la stack 1 */
        while (stack2.i_st != 0) {
          int tmp = pop(&stack2);
          push_op(&stack1, tmp);
        }
      }
      
      int calcul_npi(stack * s) {
        int n1, n2, op;
        
        if (s->i_st == 0)
          return s->st[0][0];
        if (s->st[s->i_st-1][1] == NUMER)
          return pop(s);
        
        op = s->st[s->i_st-1][0];
        pop(s);
        n1 = calcul_npi(s);
        n2 = calcul_npi(s);
        
        if (op == '+')
          return n2 + n1;
        else if (op == '-')
          return n2 - n1;
        else if (op == '*')
          return n2 * n1;
        else if (op == '/')
          return n2 / n1;
        
        /* Juste histoire de pas avoir de warning... */
        return 0;
      }
      
      int main(void) {
        char s[] = "15 + 4 / 2 - 2";
        
        memset(&stack1, 0, sizeof stack1);
        memset(&stack2, 0, sizeof stack2);
        
        convert_npi(s);
        printf("%d", calcul_npi(&stack1));
        return EXIT_SUCCESS;
      }
      

      Ce que je fait, c'est que je passe l'expression passé en NPI (notation polonaise inverse), pour que par la suite ça soit plus simple à calculer. :)
      • Partager sur Facebook
      • Partager sur Twitter
        1 septembre 2010 à 14:13:11

        C'est sympathique de ta part de lancer le truc ;) . La conversion en NPI est en effet possible et je pense que c'est la solution la plus simple pour l'exercice 2.
        • Partager sur Facebook
        • Partager sur Twitter
          1 septembre 2010 à 15:34:43

          Allez, je contribue aussi pour l'exercice 2 :
          #include <stdio.h>
          #include <stdlib.h>
          #include <errno.h>
          #include <ctype.h>
          #include <string.h>
          
          #define FATAL_ERROR(msg) {fprintf(stderr, "%s : %s\n", msg, strerror(errno)); exit(EXIT_FAILURE);}
          #define CALC_ERROR(msg) {fprintf(stderr, "%s\n", msg); error=1;}
          
          int error = 0;
          
          typedef struct Elem
          {
             double data;
             struct Elem *next;
          } Elem_t;
          
          typedef struct Stack
          {
             int size;
             struct Elem *head;
          } Stack_t;
          
          double pop (Stack_t * stack);
          
          Stack_t *init_stack (void)
          {
             Stack_t *stack = malloc (sizeof (Stack_t));
             if (stack == NULL)
                FATAL_ERROR ("Can't allocate stack");
             stack->head = NULL;
             stack->size = 0;
             return stack;
          }
          
          /*
              Détruit la pile
          */
          void destroy_stack (Stack_t ** stack)
          {
             while ((*stack)->head != NULL)
             {
                pop (*stack);
             }
             free (*stack);
             *stack = NULL;
          }
          
          /*
              Empile un élément dans la pile
          */
          void push (Stack_t * stack, double data)
          {
             Elem_t *new = malloc (sizeof (Elem_t));
             if (new != NULL)
             {
                new->data = data;
                new->next = stack->head;
                stack->head = new;
                stack->size++;
             }
          }
          
          /*
              Dépile un élement de la pile, et le retourne
          */
          double pop (Stack_t * stack)
          {
             double data = -1;
             Elem_t *tmp;
          
             if (stack->head != NULL)
             {
                data = stack->head->data;
                if (stack->head->next != NULL)
                {
                   tmp = stack->head;
                   stack->head = stack->head->next;
                   free (tmp);
                }
                else
                {
                   free (stack->head);
                   stack->head = NULL;
                }
                stack->size--;
             }
             return data;
          }
          
          /*
              Vérifie si le caractère est un opérateur
          */
          inline int is_operator (char c)
          {
             if (c == '-' || c == '+' || c == '*' || c == '/')
                return 1;
             return 0;
          }
          
          /*
              Calcule la priorité du caractère, et stock le résultat à l'endroit pointé
              par priority.
          */
          void calc_priority (char c, int *priority)
          {
             if (c == '-' || c == '+')
                *priority = 1;
             else if (c == '*' || c == '/')
                *priority = 2;
          }
          
          /*
              Calcule les deux piles, le paramètre is_para est à 1 si il faut calculer l'intérieur d'une parenthèse
          */
          void calc_piles (Stack_t * OP, Stack_t * NUM, int is_para)
          {
             double n1, n2;
             int op;
             while (OP->size >= 1 && NUM->size >= 2)
             {
                n1 = pop (NUM);
                n2 = pop (NUM);
                op = pop (OP);
          
                switch (op)
                {
                case '+':
                   push (NUM, n2 + n1);
                   break;
                case '-':
                   push (NUM, n1 - n2);
                   break;
                case '*':
                   push (NUM, n2 * n1);
                   break;
                case '/':
                   push (NUM, n1 / n2);
                   break;
                case ')':
                   if (!is_para)
                      push (OP, op);
                   push (NUM, n2);
                   push (NUM, n1);
                   return;
                   break;
                default:
                   CALC_ERROR ("Syntax error");
                   return;
                }
          
             }
          }
          
          /*
              Calcule une expression mathématique parenthésé, et retourne le résultat.
          */
          double calc_expr (char *expr)
          {
             Stack_t *OP;
             Stack_t *NUM;
             Stack_t *PRIO;
             double result;
             char *end = expr + strlen (expr) - 1;
             int last_priority = 0;
             int priority = 0;
             error = 0;
          
             OP = init_stack ();
             NUM = init_stack ();
             PRIO = init_stack ();
          
             do
             {
                /*
                   Si on a une priority plus petite que l'ancien opérateur
                   on calcule les piles, avant d'empiler le nouvel opérateur.
                 */
                calc_priority (*end, &priority);
                if (priority < last_priority)
                   calc_piles (OP, NUM, 0);
          
                /*
                   On remet la priorité à 0 si on entre dans une parenthèse.
                 */
                if (*end == ')')
                {
                  /* On empile la priorité en cours */
                   push(PRIO, last_priority);
                   priority = last_priority = 0;
                }   
                else
                   last_priority = priority;
          
                /*
                   Si on arrive à la fin d'une parenthèse, on la calcule
                 */
                if (*end == '(')
                {
                   if(PRIO->size <= 0)
                   {
                      CALC_ERROR("Brace miss!");
                      return 0;
                   }
                   calc_piles (OP, NUM, 1);
                   /* On restaure l'ancienne priorité */
                   last_priority = pop(PRIO);
                }   
                /*
                   Le ')' sert de point d'arrêt pour calculer la parenthèse
                 */
                else if (*end == ')')
                   push (OP, *end);
          
                /*
                   Si c'est un nombre, on recherche où il commence (nombres à plus de 2 caractères)
                 */
                else if (isdigit (*end))
                {
                   while ((isdigit (*end) || *end == '.') && end >= expr)
                      end--;
                   end++;   
                   push (NUM, strtod (end, NULL));
                }
                else if (is_operator (*end))
                   push (OP, *end);
                    
                else
                {
                   CALC_ERROR ("Syntax error");
                   return 0;
                }
          
             }
             while (end-- != expr);
          
             calc_piles (OP, NUM, 0);
          
             if (NUM->size != 1)
             {
                CALC_ERROR ("Syntax error");
                return 0;
             }
          
             result = NUM->head->data;
          
             destroy_stack (&OP);
             destroy_stack (&NUM);
             destroy_stack (&PRIO);
          
             return result;
          }
          
          void print_prompt (void)
          {
             printf ("\n>>>");
          }
          
          void clean_fgets_buff (char *buff)
          {
             for (; *buff && *buff != '\n'; buff++);
          
             *buff = 0;
          }
          
          int main (void)
          {
             char buffer[512];
             double result;
             printf ("******** Calc **********\n");
             print_prompt ();
             while (fgets (buffer, sizeof (buffer) - 1, stdin) != NULL)
             {
                clean_fgets_buff (buffer);
                result = calc_expr (buffer);
                if (!error)
                   printf ("%g", calc_expr (buffer));
                print_prompt ();
             }
             return 0;
          }
          


          Pas mal d'erreurs non gérées, et certaines parties du code sont mal foutues. Il doit rester encore des cas que je ne gère pas (par exemple le : (-1*4) ne sera pas considéré comme juste), mais sur les exemples généraux, le résultat semble satisfaisant.
          • Partager sur Facebook
          • Partager sur Twitter
            1 septembre 2010 à 16:17:13

            T'as un problème de priorité pour les parenthèses. :)

            >>>4+(5+1)*(4+2)
            60
            • Partager sur Facebook
            • Partager sur Twitter
              1 septembre 2010 à 16:31:04

              Effectivement, je viens d'éditer pour corriger.
              J'utilise maintenant une troisième pile pour gérer les priorités, ça commence peut être à faire beaucoup...
              • Partager sur Facebook
              • Partager sur Twitter
                1 septembre 2010 à 20:51:06

                Est ce qu'il y aurait moyen de "fournir" une batterie de petit test pour le parseur de l'exo 2 ? ^^
                J'ai codé un truc (c'est très brouillon pour le moment, voir ci dessous), mais j'ai peur d'avoir raté un truc...
                Bref, voici mes codes :
                Exo 1 (je vide uniquement le buffer après une entrée, je ne vérifie pas les entrées de façon "clean") :

                #include <stdio.h>
                
                void zCalc1(void)
                {
                    int val = 0, tmp = 0;
                    char op = '+';
                    
                    while (1)
                    {
                	printf("Entrez un nombre : ");
                	scanf("%d",&tmp);
                	while (getchar() != '\n') ;
                
                	if (op == '+')
                	    val += tmp;
                	else if (op == '-')
                	    val -= tmp;
                	else if (op == '*')
                	    val *= tmp;
                	else if (op == '/')
                	    val /= tmp;
                
                	printf("Quelle opération (+, -, *, /, c, q) : %d ",val);
                	op = getchar();
                	while (getchar() != '\n') ;
                
                	if (op == 'q')
                	    break ;
                		else if (op == 'c')
                	{
                	    val = 0;
                	    continue ;
                	}
                    }
                }
                
                int main(int argc, char *argv[])
                {
                    zCalc1();
                    return 0;
                }
                

                Exo 2 (aucun test sur la validité d'une expression, c'est très brouillon comme dis plus haut... Si vous avez des conseils, je suis totalement preneur ;) ) :
                #include <stdio.h>
                #include <stdlib.h>
                #include <ctype.h>
                #include <string.h>
                
                #define ABS(x) (((x) > 0) ? (x) : -(x))
                
                double result = 0;
                
                double parse (char **s, char end);
                
                double get_numb(char **s, char end)
                {
                    double res = 1, tmp = 0;
                    if (!strncmp(*s,"ans",3))
                    {
                	res = result;
                	(*s) += 3;
                    }
                    else if (isdigit(**s))
                	res = strtod(*s,s);
                
                    while (**s != end && **s != '\0' && **s != '+' && **s != '-')
                    {
                	if (**s == '*')
                	{
                	    (*s) ++;
                	    if (**s == '(')
                	    {
                		(*s) ++;
                		res *= parse(s,')');
                		(*s) ++;
                	    }
                	    else
                	    {
                		if (!strncmp(*s,"ans",3))
                		{
                		    res *= result;
                		    (*s) += 3;
                		}
                		else
                		    res *= strtod(*s,s);
                	    }
                	}
                	else if (**s == '/')
                	{
                	    (*s) ++;
                	    if (**s == '(')
                	    {
                		(*s) ++;
                		tmp = parse(s,')');
                		if (ABS(tmp) < 0.000001)
                		{
                		    printf("Zéro division !\n");
                		    exit(0);
                		}
                		res /= tmp;
                		(*s) ++;
                	    }
                	    else
                	    {
                		if (!strncmp(*s,"ans",3))
                		{
                		    res /= result;
                		    (*s) += 3;
                		}
                		else
                		    res /= strtod(*s,s);
                	    }
                	}
                	else if (**s == '(')
                	{
                	    (*s) ++;
                	    res = parse(s,')');
                	    (*s) ++;
                	}
                
                    }
                    return res;
                }
                
                double parse (char **s, char end)
                {
                    double res = 0, tmp = 0;
                
                    while (**s != end && **s != '\0')
                    {
                	if (isdigit(**s))
                	{
                	    res += get_numb(s,end);
                	}
                	else if (**s == '(')
                	{
                	    (*s) ++;
                	    res += parse(s,')');
                	    printf("%s\n",*s);
                	    (*s) ++;
                	}
                	else
                	{
                	    switch(**s)
                	    {
                	    case '+':
                		(*s) ++;
                		res += get_numb(s,end);
                		break;
                	    case '-':
                		(*s) ++;
                		res -= get_numb(s,end);
                		break;
                	    case '*':
                		(*s) ++;
                		res *= get_numb(s,end);
                		break;
                	    case '/':
                		(*s) ++;
                		tmp = get_numb(s,end);
                		if (ABS(tmp) < 0.000001)
                		{
                		    printf("Zéro division !\n");
                		    exit(0);
                		}	
                		res /= tmp;
                		break;
                	    default: (*s) ++; break;
                	    }
                	}
                    }
                
                    return res;
                }
                
                char *modif_line(char *s)
                {
                    int cmp = 0;
                    int i,j;
                    char *res = NULL;
                
                    for (i=0; s[i] != '\0'; i++)
                	if (s[i] != ' ')
                	    cmp ++;
                
                    res = malloc((cmp+1)*sizeof(char));
                    
                    for (i=0,j=0; s[i] != '\0'; i++)
                	if (s[i] != ' ')
                	{
                	    res[j] = s[i];
                	    j ++;
                	}
                    res[j] = '\0';
                    
                    free(s);
                    return res;
                }
                
                int main(void)
                {
                    char *s,*tmp;
                    s = malloc(100*sizeof(char));
                    scanf("%[^\n]100s",s);
                    s = modif_line(s);
                    tmp = s;
                    printf("%s = %f\n",tmp,(result = parse(&s,'\0')));
                    free(tmp);
                
                    return 0;
                }
                

                Le code gère (en théorie... ) la priorité des opérateurs et des parenthèses, il ne marche pour le moment qu'avec des ints (pas grand chose à modifier pour utiliser les doubles of course, je ferais un édit dans la soirée avec).

                PRECISION IMPORTANTE : Le code ne gère pas les espaces !
                Je m'aperçois que je n'ai pas géré l'utilisation de ans :p

                Edit : Modification du 2ème code pour la gestion des nombres décimaux. Je précise que en théorie, le code ne devrait pas planter sur des entrées correctes (si c'est le cas, merci de me le dire ;) ), en revanche il peut sortir des résultats abberants ou planter sur des entrées incorrectes (*1 = 0, *(2+3) plante, etc... ).

                Edit 2 : Modification du 2ème code, normalement il gère les espaces maintenant et préviens en cas de division par zéro, de plus il devrait prévenir si une expression est incorrecte (il doit y en avoir qui passent encore par mon vérificateur par contre ;) )
                • Partager sur Facebook
                • Partager sur Twitter
                  1 septembre 2010 à 21:01:00

                  Salut,

                  Voici mon code (vraiment pourri par rapport aux autres :p )

                  Avancement actuel:
                  -operateurs geres : */-+^
                  -parentheses : non
                  -Math Error : oui
                  -commentaires : oui

                  #include <stdio.h>
                  #include <stdlib.h>
                  #include <string.h>
                  
                  #define PUISSANCE 0
                  #define MULTIPLIER 1
                  #define DIVISER 2
                  #define ADDITIONNER 3
                  #define SOUSTRAIRE 4
                  #define OPERATEURS_GERES 5
                  
                  #define MATH_ERROR 156879
                  
                  int calculerExpression(char* expression);
                  int rechercherPOperateur(const char* expression);
                  int typeOperateur(const char* expression, int pOperateur);
                  int rechercherN1(char* expression, int pOperateur);
                  int rechercherN2(const char* expression, int pOperateur);
                  int rechercherPN2(const char* expression, int pOperateur);
                  int rechercherPN2(const char* expression, int pOperateur);
                  void actualiserExpression(char* expression, int pOperateur, int ans);
                  int traduireNombre(char* nombre);
                  int operationResolue(const char* expression);
                  int calcul(int n1, int n2, int operateur);
                  
                  int calculerExpression(char* expression) // fonction principale de traitement de l'expression
                  {
                      int Poperateur = -1, operateur = 0;
                      int n1 = 0, n2 = 0, ans = 0;
                  
                      while(operationResolue(expression) == 0)
                      {
                          Poperateur = rechercherPOperateur(expression);
                          /* pOperateur est la position de l'operateur prioritaire dans la chaine */
                          operateur = typeOperateur(expression, Poperateur);
                          /* operateur correspond à une constante (MULTIPLIER, PUISSANCE ...) */
                          n1 = rechercherN1(expression, Poperateur); 
                          n2 = rechercherN2(expression, Poperateur);
                          ans = calcul(n1, n2, operateur);
                          if(ans == MATH_ERROR)
                              return MATH_ERROR;
                  
                          actualiserExpression(expression, Poperateur, ans); 
                          /* cette fonction remplace l'operation effectuee avant par 
                          le résultat dans la chaine expression */
                      }
                  
                      return traduireNombre(expression);
                      /* traduireNombre() convertit un nombre de type char* en type int */
                  }
                  
                  int rechercherPOperateur(const char* expression) 
                  /* retourne la position de l'operateur */
                  {
                      for(int i = 0 ; i < OPERATEURS_GERES ; i ++)
                      {
                          for(int j = 0 ; j < strlen(expression) ; j ++)
                          {
                              switch(i)
                              {
                                  case PUISSANCE:
                                  if(expression[j] == '^')
                                      return j;
                                  break;
                  
                                  case MULTIPLIER:
                                  case DIVISER:
                                  if(expression[j] == '*' || expression[j] == '/')
                                      return j;
                                  break;
                                  case ADDITIONNER:
                                  case SOUSTRAIRE:
                                  if(expression[j] == '+' || expression[j] == '-')
                                      return j;
                                  break;
                                  default:
                                  break;
                              }
                          }
                      }
                      return -1;
                  }
                  
                  int typeOperateur(const char* expression, int pOperateur) 
                  /* retourne la constante correspondant à l'opérateur */
                  {
                      switch(expression[pOperateur])
                      {
                          case '^':
                          return PUISSANCE;
                          break;
                          case '*':
                          return MULTIPLIER;
                          break;
                          case '/':
                          return DIVISER;
                          break;
                          case '+':
                          return ADDITIONNER;
                          break;
                          case '-':
                          return SOUSTRAIRE;
                          break;
                          default:
                          return -1;
                          break;
                      }
                  }
                  
                  int rechercherN1(char* expression, int pOperateur)
                  {
                      char* nombreEnLettres = malloc(2);
                      int i = pOperateur - 1, j = 2;
                  
                      nombreEnLettres[0] = expression[i];
                      nombreEnLettres[1] = '\0';
                      i --;
                  
                      while(typeOperateur(expression, i) == -1 && i >= 0)
                      {
                          j ++;
                          realloc(nombreEnLettres, j);
                  
                          nombreEnLettres[j] = '\0';
                          for(int k = j - 1 ; k >= 0 ; k --)
                              nombreEnLettres[k] = nombreEnLettres[k - 1];
                  
                  
                          nombreEnLettres[0] = expression[i];
                          i --;
                      }
                  
                      return traduireNombre(nombreEnLettres);
                  }
                  
                  int rechercherN2(const char* expression, int pOperateur)
                  {
                      char* nombreEnLettres = malloc(1);
                      int i = pOperateur + 1, j = 1;
                  
                      nombreEnLettres[0] = expression[i];
                      i ++;
                      nombreEnLettres[1] = '\0';
                  
                      while(typeOperateur(expression, i) == -1 && expression[i] != '\0')
                      {
                          j ++;
                          realloc(nombreEnLettres, j);
                  
                          nombreEnLettres[j - 1] = expression[i];
                          nombreEnLettres[j] = '\0';
                          i ++;
                      }
                  
                      return traduireNombre(nombreEnLettres);
                  }
                  
                  int rechercherPN1(const char* expression, int pOperateur) 
                  /* recherche le debut de l'operation (donc le debut de n1) */
                  {
                      int i = pOperateur - 1;
                  
                      while(typeOperateur(expression, i) == -1 && i >= 0)
                          i --;
                  
                      i ++;
                  
                      return i;
                  }
                  
                  int rechercherPN2(const char* expression, int pOperateur)
                  /* recherche la fin de l'operation (donc la fin de n2) */
                  {
                      int i = pOperateur + 1;
                  
                      while(typeOperateur(expression, i) == -1 && expression[i] != '\0')
                          i ++;
                  
                      return i;
                  }
                  
                  void actualiserExpression(char* expression, int pOperateur, int ans)
                  {
                      int debutChaine = 0, finChaine = 0, tailleChaine = 0;
                      char* memChaine = NULL;
                  
                      debutChaine = rechercherPN1(expression, pOperateur);
                      finChaine = rechercherPN2(expression, pOperateur);
                  
                      memChaine = malloc(strlen(expression + finChaine));
                      strcpy(memChaine, expression + finChaine);
                  
                      sprintf(expression + debutChaine, "%d", ans);
                      tailleChaine = strlen(expression);
                  
                      strcat(expression, memChaine);
                  
                  
                  }
                  
                  int traduireNombre(char* nombre)
                  /* convertit un char* en int */
                  {
                      int n = 0, puissance = 1;
                  
                      for(int i = strlen(nombre) - 1 ; i >= 0 ; i --)
                      {
                          n += (nombre[i] - '0')*puissance;
                          puissance *= 10;
                      }
                  
                      return n;
                  }
                  
                  int operationResolue(const char* expression)
                  /* verifie si l'operation est completement resolue ou non */
                  {
                      if(rechercherPOperateur(expression) == -1)
                          return 1;
                  
                      return 0;
                  }
                  
                  int calcul(int n1, int n2, int operateur)
                  {
                      int result = 0;
                      switch(operateur)
                      {
                          case MULTIPLIER:
                          return n1*n2;
                          break;
                  
                          case DIVISER:
                          if(n2 != 0)
                              return n1/n2;
                          else
                              return MATH_ERROR;
                          break;
                  
                          case ADDITIONNER:
                          return n1+n2;
                          break;
                  
                          case SOUSTRAIRE:
                          return n1 - n2;
                          break;
                  
                          case PUISSANCE:
                          result = n1;
                          for(int i = 1 ; i < n2 ; i ++)
                              result *= n1;
                          return result;
                  
                          default:
                          return SYNTAX_ERROR;
                          break;
                      }
                  }
                  
                  int main()
                  {
                      char expression[1000] = "5^3+2+6";
                      int result = 0;
                  
                      for(int i = 0 ; i < 5 ;  i++)
                      {
                          scanf("%s", expression);
                          if((result = calculerExpression(expression)) == MATH_ERROR)
                              printf("\nMATH ERROR!\n");
                          else
                              printf("= %d\n", result);
                      }
                  
                      return 0;
                  }
                  
                  • Partager sur Facebook
                  • Partager sur Twitter
                    1 septembre 2010 à 22:41:38

                    @Holt : La solution de l'exercice 1 a un bug quand on utilise la commande c (clear). Autrement je suis jaloux :p (ton code il est deux fois plus court que le mien mais moins bien découpé).
                    Ensuite, pour l'exercice 2, je n'ai pas vu d'erreurs en sortie. Par contre, ta façon de gérer la priorité des opérateurs est plutôt spéciale. Et je regrette que tu n'ai pas plus découpé ton code.
                    Je vais voir pour une batterie de tests (mais je promets rien)

                    @alex922 : ça à l'air pas mal (j'ai pas encore testé) mais si tu rajoutais quelques commentaires se ne serait pas de refus. De même l'indentation n'est pas parfaite à certains endroits.
                    • Partager sur Facebook
                    • Partager sur Twitter
                      1 septembre 2010 à 22:47:25

                      Voilà une version améliorée qui gère les variables. :)

                      #include <stdio.h>
                      #include <stdlib.h>
                      #include <ctype.h>
                      #include <string.h>
                      
                      #define N_MAX 1000
                      
                      enum { VIDE, NUMER, OPER };
                      
                      typedef struct stack_s {
                        int st[N_MAX][2];
                        int i_st;
                      } stack;
                      
                      typedef struct variables_s {
                        char nom[50];
                        int len_nom;
                        int val;
                        struct variables_s * suiv;
                      } variables;
                      
                      #pragma mark Globales
                      stack stack1;
                      stack stack2;
                      variables vars;
                      
                      variables * creer_var(char * nom, int val) {
                        variables * tmp = malloc(sizeof *tmp);
                        
                        if (tmp == NULL) {
                          fprintf(stderr, "Erreur d'allocation: %s\n", nom);
                          return NULL;
                        }
                        strcpy(tmp->nom, nom);
                        tmp->val = val;
                        tmp->len_nom = strlen(nom);
                        tmp->suiv = NULL;
                        
                        return tmp;
                      }
                      
                      void set_var(char * nom, int val) {
                        int exists = 0;
                        variables * v = &vars;
                        
                        /* Regarde si la variable existe */
                        variables * tmp = v->suiv;
                        while (1) {
                          if (strcmp(v->nom, nom) == 0) {
                            exists = 1;
                            break;
                          }
                          if (tmp == NULL)
                            break;
                          v = tmp;
                          tmp = tmp->suiv;
                        }
                        
                        if (exists) {
                          v->val = val;
                        }
                        else {
                          /* Si elle n'existe pas, on la crée */
                          if (!v)
                            v = creer_var(nom, val);
                          else
                            v->suiv = creer_var(nom, val);
                        }
                      }
                      
                      int isoper(int n) {
                        char oper[] = { '+', '-', '*', '/', '(', ')' };
                        int sz = sizeof oper / sizeof *oper;
                        int i;
                        
                        for (i = 0; i < sz; i++)
                          if (n == oper[i])
                            return 1;
                        return 0;
                      }
                      
                      int set_prio(int op) {
                        int i, sz;
                        struct {
                          char op;
                          int val;
                        } equ[] = {
                          { '(', 0 },
                          { '+', 1 },
                          { '-', 2 },
                          { '*', 3 },
                          { '/', 4 }
                        };
                        
                        sz = sizeof equ / sizeof *equ;
                        for (i = 0; i < sz; i++)
                          if (op == equ[i].op)
                            return equ[i].val;
                        
                        /* Opérateur pas dans la liste */
                        return 0;
                      }
                      
                      /* Retourne la priorité de op1 par rapport à op2 */
                      /* '(' < '+' < '-' < '*' < '/' */
                      int priorite(int op1, int op2) {
                        op1 = set_prio(op1);
                        op2 = set_prio(op2);
                        return op1 > op2;
                      }
                      
                      void push(stack * s, int n, int type) {
                        s->st[s->i_st][0] = n;
                        s->st[s->i_st][1] = type;
                        s->i_st++;
                      }
                      
                      int pop(stack * s) {
                        int tmp = s->st[s->i_st-1][0];
                        s->st[s->i_st-1][0] = VIDE;
                        s->st[s->i_st-1][1] = VIDE;
                        s->i_st--;
                        return tmp;
                      }
                      
                      /* Retourne l'indice de la variable dans la liste chaînée */
                      /* -1 -> Erreur
                       *  0 -> Existe
                       * >0 -> N'existe pas */
                      int var_exists(char * (*s)) {
                        char nom[50] = "";
                        int i;
                        int exists = 0;
                        variables * v = &vars;
                        
                        /* Recupere le nom de la variable */
                        i = 0;
                        while (isalpha(**s)) {
                          nom[i] = **s;
                          (*s)++;
                          i++;
                        }
                        nom[i] = '\0';
                        
                        /* Regarde si la variable existe */
                        /* i sert pour la position dans la liste chaînée */
                        i = 1;
                        while (v != NULL) {
                          if (strncmp(v->nom, nom, v->len_nom) == 0) {
                            exists = 1;
                            break;
                          }
                          i++;
                          v = v->suiv;
                        }
                        
                        /* On vérifie si il s'agit d'une affectation */
                        while (isspace(**s))
                          (*s)++;
                        
                        if (**s == '=') {
                          /* Crée la variable si elle n'existe pas */
                          if (!exists)
                            set_var(nom, 0);
                          (*s)++;
                          return i;
                        }
                        
                        if (exists) {
                          if (isoper(v->val))
                            push(&stack1, v->val, OPER);
                          else
                            push(&stack1, v->val, NUMER);
                        }
                        else {
                            return -1;
                        }
                        
                        return 0;
                      }
                      
                      void supp_elem_var(int ind) {
                        int i;
                        variables * v = &vars;
                        variables * tmp_prev;
                        variables * tmp_nxt;
                        
                        for (i = 1; i < ind; i++)
                          v = v->suiv;
                        
                        tmp_prev = v;
                        tmp_nxt = v->suiv->suiv;
                        free(v);
                        tmp_prev->suiv = tmp_nxt;
                      }
                      
                      char * set_elem_var(int ind, int val) {
                        int i;
                        variables * v = &vars;
                        
                        for (i = 1; i < ind; i++)
                          v = v->suiv;
                        
                        set_var(v->nom, val);
                        return v->nom;
                      }
                      
                      /* La stack 1 sert pour la NPI, la stack 2 pour les opérateurs */
                      /* Une fois la fonction finie, seule la stack 1 est remplie */
                      
                      /* Retourne l'indice de la variable dans la liste chaînée */
                      /* -1 -> Erreur
                       *  0 -> Fonction 'normale' de calcul
                       * >0 -> Position dans la liste chaînée */
                      int convert_npi(char * s) {
                        int prem = 1;
                        int var_trouve = -1;
                        
                        while (*s) {
                          /* On vide les blancs */
                          while (isspace(*s))
                            s++;
                          
                          /* Si c'est une variable */
                          if (isalpha(*s)) {
                            int tmp = var_exists(&s);
                            /* Variable créée si elle n'existe pas, la supprimer si
                             * l'affectation n'est pas bonne */
                            if (tmp > 0 && prem)
                              var_trouve = tmp;
                            else if (tmp > 0 && !prem) {
                              fputs("Erreur d'affectation.", stderr);
                              /* Supprime la variable créée précédement */
                              supp_elem_var(tmp);
                              return -1;
                            }
                            else if (tmp < 0)
                              fputs("Variable inexistante.", stderr);
                          }
                          /* Si c'est un nombre */
                          else if (isdigit(*s)) {
                            push(&stack1, strtol(s, &s, 10), NUMER);
                          }
                          /* Si c'est un opérateur */
                          else if (isoper(*s)) {
                            /* On ajoute sur la stack 2 si elle est vide ou si on a
                             * une parenthèse */
                            if (stack2.i_st == 0 || *s == '(') {
                              push(&stack2, *s, OPER);
                            }
                            /* Sinon, on regarde si c'est un parenthèse fermante */
                            else if (*s == ')') {
                              /* Si c'est le cas, on dépop toute la stack 2
                               * jusqu'à la parenthèse */
                              while (stack2.st[stack2.i_st-1][0] != '(') {
                                int tmp = pop(&stack2);
                                push(&stack1, tmp, OPER);
                              }
                              pop(&stack2);
                            }
                            /* Sinon on regarde la priorité des opérateurs.
                             * Si l'opérateur en cours a une prio plus importante, on le stocke,
                             * sinon on depop sur la stack 1 */
                            else {
                              if (priorite(*s, stack2.st[stack2.i_st-1][0]) == 1) {
                                push(&stack2, *s, OPER);
                              }
                              else {
                                /* Tant que la prio de l'op en cours est inférieure à celle
                                 * sur la stack, on dépile sur la stack 1 */
                                while (priorite(*s, stack2.st[stack2.i_st-1][0]) != 1) {
                                  int tmp = pop(&stack2);
                                  push(&stack1, tmp, OPER);
                                }
                                /* On mets l'op sur la stack 2 */
                                push(&stack2, *s, OPER);
                              }
                            }
                            /* On passe l'opérateur */
                            s++;
                          }
                          /* Ce n'est plus le premier tour de boucle */
                          prem = 0;
                        }
                        
                        /* Une fois que la chaîne est vide,
                         * il faut vider la stack 2 sur la stack 1 */
                        while (stack2.i_st != 0) {
                          int tmp = pop(&stack2);
                          push(&stack1, tmp, OPER);
                        }
                        
                        return var_trouve < 0 ? 0 : var_trouve;
                      }
                      
                      int calcul_npi(stack * s) {
                        int n1, n2, op;
                        
                        if (s->i_st == 0)
                          return s->st[0][0];
                        if (s->st[s->i_st-1][1] == NUMER)
                          return pop(s);
                        
                        op = s->st[s->i_st-1][0];
                        pop(s);
                        n1 = calcul_npi(s);
                        n2 = calcul_npi(s);
                        
                        if (op == '+')
                          return n2 + n1;
                        else if (op == '-')
                          return n2 - n1;
                        else if (op == '*')
                          return n2 * n1;
                        else if (op == '/') {
                          if (n1 == 0) {
                            fputs("Division par 0, remplacée par 1.", stderr);
                            n1 = 1;
                          }
                          return n2 / n1;
                        }
                        
                        /* Juste histoire de pas avoir de warning... */
                        return 0;
                      }
                      
                      void virer_entree(char * s) {
                        char * c = strchr(s, '\n');
                        
                        if (c)
                          *c = '\0';
                      }
                      
                      void prompt(void) {
                        int done = 0;
                        char s[N_MAX] = "";
                        int affect;
                        int calc;
                        
                        while (!done) {
                          memset(&stack1, 0, sizeof stack1);
                          memset(&stack2, 0, sizeof stack2);
                          
                          printf(">>> ");
                          fgets(s, N_MAX, stdin);
                          virer_entree(s);
                          
                          if (strcmp(s, "quit") == 0 || strchr(s, 'q'))
                            return;
                          else if (strchr(s, 'c'))
                            set_var("ans", 0);
                          else {
                            affect = convert_npi(s);
                            
                            if (affect >= 0) {
                              calc = calcul_npi(&stack1);
                            }
                            
                            if (affect > 0)
                              printf("%s = ", set_elem_var(affect, calc));
                            
                            printf("%d\n", calc);
                            set_var("ans", calc);
                          }
                        }
                      }
                      
                      int main(void) {
                        strcpy(vars.nom, "ans");
                        vars.len_nom = 3;
                        vars.val = 0;
                        vars.suiv = NULL;
                        
                        prompt();
                        return EXIT_SUCCESS;
                      }
                      

                      J'ai fait quelques modifs de dernière minute, il se peut qu'il reste quelques bugs. :-°
                      Encore une fois, je considère que l'utilisateur est intelligent. :-°

                      @ Holt : T'as essayé l'entrée que j'ai montré plus bas ? :-°
                      Avec cette entrée je tombe en boucle infinie. :)
                      4+(5+1)*(4+2)

                      @ alex922 : Ton code n'est pas pourri... au moins tu as fait quelque chose ! Et ça à l'air de fonctionner correctement (j'ai pas réussi à la mettre en faute ;) ).
                      Tu peux essayer de mettre les parenthèses ou de factoriser ton code maintenant. :)
                      • Partager sur Facebook
                      • Partager sur Twitter
                        2 septembre 2010 à 8:39:10

                        Merci !

                        J'ai édité avec des commentaires et je gère maintenant les puissances.

                        Je m'attaque aux parentheses, j'essayerai de factoriser ensuite.
                        • Partager sur Facebook
                        • Partager sur Twitter
                          2 septembre 2010 à 10:51:35

                          Alex922, tu n'as pas oublié la définition de tes constantes dans ton dernier édit?

                          Sinon, j'ai tenté une approche récursive, mais ce n'est pas encore fameux pour l'instant... :euh:
                          • Partager sur Facebook
                          • Partager sur Twitter
                            2 septembre 2010 à 11:22:40

                            @Tosh oups merci c'est fait

                            moi aussi j'en suis aux parentheses, j'ai fini mon code sauf que code bloks ne veut pas le lancer(has not been built yet, puis exit status 1). Je créerai un nouveau sujet si je n'y arrive pas.
                            • Partager sur Facebook
                            • Partager sur Twitter
                              2 septembre 2010 à 11:58:24

                              @Pouet : Je n'ai pas testé ton code mais j'ai vu que tu utilise une liste chainée pour les variables ce qui est très couteux. Une table de hachage serait sans doute plus appropriée.

                              En tout cas, ça fait plaisir de voir que l'exercice a un peu de succès.
                              • Partager sur Facebook
                              • Partager sur Twitter
                                2 septembre 2010 à 12:08:45

                                Ouais mais c'est simple a implémenter. :lol:
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  2 septembre 2010 à 15:47:49

                                  Citation : Pouet_forever

                                  @ Holt : T'as essayé l'entrée que j'ai montré plus bas ? :-°
                                  Avec cette entrée je tombe en boucle infinie. :)
                                  4+(5+1)*(4+2)


                                  Mouais à mon avis je suis mal parti, je me disais bien que le code était très mal pensé :-°
                                  Je reposterais quelque chose de "totalement" différent quand j'aurai le temps ;)
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    2 septembre 2010 à 15:52:42

                                    Pouet forever ton truc il est cool mais ne gère pas plus les virgules que ma petite soeur :lol:

                                    oups, je n'ai pas de petite soeur...
                                    **Ultima sort**
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      2 septembre 2010 à 16:00:51

                                      @Ultimachaos : Trop cool, et le tien il gère quoi ? :-°
                                      Plutôt que de faire des réflexions stupides et dénuées d'intérêt montre nous ce que tu sais faire.
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        2 septembre 2010 à 16:06:53

                                        ne me tentes pas, je n'arriverai à rien :lol:
                                        excuse moi si je t'ai provoqué, ce n'était pas mon but ;)
                                        et sache que je connais pouet forever car nous avons participé à un concours il y a pas mal de temps, et que c'est la seul raison pour laquelle je me suis permis de commanter son code ^^

                                        Oui, je pense que pouet forever et capable de refaire son code pour gérer les décimales, et je suis même étonné qu'il n'y ai pas pensé :)
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          2 septembre 2010 à 16:44:36

                                          @Ultimachaos : Rajouter la gestion des décimales n'est pas bien compliqué en soit (le principal étant de géré les entiers, la gestion des décimales n'est qu'un plus).

                                          Autrement, quand tu dis que tu n'arriveras à rien, tu te trompe le premier niveau de l'exercice est très faisable. Par contre, c'est sur que si tu pars du principe que tu échoueras alors tu n'arriveras à rien.
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            2 septembre 2010 à 16:50:52

                                            Citation : Lithrein

                                            @Ultimachaos : Rajouter la gestion des décimales n'est pas bien compliqué en soit (le principal étant de géré les entiers, la gestion des décimales n'est qu'un plus).


                                            Je voyais plutôt un nouveau type de variable remplaçant double, ce qui permettrai d'avoir une précision supérieur et d'éviter les 0 en fin de nombre.
                                            J'imaginais surtout un jeu de conversion char/int avec une chaine de char qui recueillerai la réponse finale chiffre par chiffre et qui finirait clairement le nombre par un \0.

                                            Citation : Lithrein

                                            Autrement, quand tu dis que tu n'arriveras à rien, tu te trompe le premier niveau de l'exercice est très faisable. Par contre, c'est sur que si tu pars du principe que tu échoueras alors tu n'arriveras à rien.


                                            je n'ai jamais dis que je n'y arriverai pas parce que je n'ai pas les compétence ou que l'exercice est trop dur :)

                                            (ça sent la manipulation à plein nez, tu veux me faire participer à ton exercice et tu es en train de réussir :p )
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              2 septembre 2010 à 17:08:01

                                              Pour gérer les décimales je n'ai qu'une seule ligne à changer (et tous les types). Je remplace strtol par strtod. :-°
                                              J'aime pas les flottants, je trouve que ça obscurci le code inutilement, c'est pour ça que j'ai choisi de rester sur des entiers. ;)

                                              (Quel concours ? :-° )
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                2 septembre 2010 à 17:10:00

                                                L'autre il en a fait tellement qu'il ne se rappelle même pas de moi :lol:
                                                celui fait par cambui, le tournoi en console ;)

                                                sinon t'en penses quoi de mon idée de remplacer le double par autre chose?
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  2 septembre 2010 à 17:18:18

                                                  Le but c'est pas de créer un nouveau type de variable. Tu peux utiliser... printf par exemple. :-°

                                                  #include <stdio.h>
                                                  #include <stdlib.h>
                                                  #include <math.h>
                                                  
                                                  int main(void) {
                                                    double pi = 4 * atan(1);
                                                    printf("%g", pi);
                                                    return EXIT_SUCCESS;
                                                  }
                                                  

                                                  3.14159
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    2 septembre 2010 à 17:19:44

                                                    ok je m'avoue vaincu par ton %g ^^
                                                    edit: finalement, non! celui-ci manque de précision, il s'arrête trop tôt pour moi :p

                                                    depuis quand 3,000004 = 3?
                                                    int main()
                                                    {
                                                        double test = 3.000004;
                                                        printf("%f\n", test);
                                                        printf("%g\n", test);
                                                    }
                                                    
                                                    3.000004
                                                    3
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      2 septembre 2010 à 17:36:34

                                                      Ca part un peu en HS là :p

                                                      J'ai modif mon code plus haut, en fait j'avais juste oublié d'un petit (*s) ++; ><
                                                      J'ai rajouté une fonction pour virer les espaces (je préfère passer ma chaine par une fonction qui les vires, plutôt que de devoir le gérer dans la fonction qui parse l'expression).
                                                      Le code n'est peut être pas si pourri que ça algorithmiquement en fait :p Mais bon, quand j'aurais le temps je retravaillerai le découpage, etc...
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        2 septembre 2010 à 18:16:51

                                                        @ Holt : Ca marche, pas réussi à mettre ton code en défaut. :)

                                                        @ Ultimachaos :
                                                        Effectivement tu as participé au concours, mais je ne t'ai jamais parlé, donc dire qu'on se connait... . Essaye de faire en sorte que tes posts soient utiles, là ce n'est pas le cas, je qualifierai presque ça de flood, fais ça sur d'autres topics.
                                                        Fais un post constructif : Fais l'exercice !

                                                        Pour le %g, effectivement, mais si ça ne te plait pas, tu peux toujours créer ta propre fonction pour le faire à ta guise (vu la précision des flottants, dire que 3.000004 n'est pas égal à 3, c'est pousser mémé dans les orties, et est-ce que tu as vraiment besoin d'une telle précision ?).
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          2 septembre 2010 à 18:41:57

                                                          Voilà, une nouvelle version de mon Zcalc!

                                                          #include <stdio.h>
                                                          #include <stdlib.h>
                                                          #include <errno.h>
                                                          #include <ctype.h>
                                                          #include <string.h>
                                                          #include <math.h>
                                                          
                                                          #define CALC_ERROR(msg) {fprintf(stderr, "%s\n", msg); error=1;}
                                                          
                                                          int error = 0;
                                                          double ans = 0;
                                                          
                                                          /**************************************
                                                              * Gestion des piles statiques.
                                                          ***************************************/
                                                          #define STACK_SIZE 512
                                                          
                                                          typedef struct Stack
                                                          {
                                                             double data[STACK_SIZE];
                                                             int head;
                                                          } Stack_t;
                                                          
                                                          void init_stack (Stack_t * s)
                                                          {
                                                             memset (s, 0, sizeof (Stack_t));
                                                          }
                                                          
                                                          void push_stack (Stack_t * s, double data)
                                                          {
                                                             if (s->head >= STACK_SIZE)
                                                                return;
                                                             s->data[s->head] = data;
                                                             s->head++;
                                                          }
                                                          
                                                          double pop_stack (Stack_t * s)
                                                          {
                                                             if (s->head == 0)
                                                                return -1;
                                                             s->head--;
                                                             return s->data[s->head];
                                                          }
                                                          
                                                          int stack_size (Stack_t * s)
                                                          {
                                                             return s->head;
                                                          }
                                                          
                                                          /********************************
                                                              * Gestion des keywords
                                                          *********************************/
                                                          #define MAX_KEYWORD_LEN 50
                                                          
                                                          void ans_callback (Stack_t * num)
                                                          {
                                                             push_stack (num, ans);
                                                          }
                                                          
                                                          void sqrt_callback (Stack_t * num)
                                                          {
                                                             double n;
                                                             if(stack_size(num) <= 0)
                                                             {
                                                                CALC_ERROR("Syntax error");
                                                                return;
                                                             }
                                                             n = pop_stack (num);
                                                             if(n <= 0)
                                                             {
                                                                CALC_ERROR("sqrt < zéro!");
                                                                return;
                                                             }
                                                             push_stack (num, sqrt (n));
                                                          }
                                                          
                                                          void cos_callback (Stack_t *num)
                                                          {
                                                             double n;
                                                             if(stack_size(num) <= 0)
                                                             {
                                                                CALC_ERROR("Syntax error");
                                                                return;
                                                             }
                                                             n = pop_stack (num);
                                                              push_stack (num, cos(n));
                                                          }
                                                          void sin_callback (Stack_t *num)
                                                          {
                                                             double n;
                                                             if(stack_size(num) <= 0)
                                                             {
                                                                CALC_ERROR("Syntax error");
                                                                return;
                                                             }
                                                             n = pop_stack (num);
                                                              push_stack (num, sin(n));
                                                          }
                                                          typedef struct Keyword
                                                          {
                                                             char name[MAX_KEYWORD_LEN];
                                                             void (*callback) (Stack_t *);
                                                          } Keyword_t;
                                                          
                                                          Keyword_t keywords[] = {
                                                             {"ans", &ans_callback},
                                                             {"sqrt", &sqrt_callback},
                                                             {"cos", &cos_callback},
                                                             {"sin", &sin_callback},
                                                             {"", NULL}
                                                          };
                                                          
                                                          /* 
                                                              Recherche un mot clef dans la liste, retourne -1 si
                                                              il n'existe pas.
                                                          */
                                                          int search_keyword (char *name)
                                                          {
                                                             int i;
                                                             for (i = 0; keywords[i].callback != NULL; i++)
                                                             {
                                                                if (!strcmp (keywords[i].name, name))
                                                                   return i;
                                                             }
                                                             return -1;
                                                          }
                                                          
                                                          /**************************************
                                                              * Gestion des variables
                                                          **************************************/
                                                          #define MAX_NAME_LEN 50
                                                          #define MAX_VARS 100
                                                          
                                                          typedef struct Var
                                                          {
                                                             char name[MAX_NAME_LEN];
                                                             double data;
                                                          } Var_t;
                                                          
                                                          int n_vars = 0;
                                                          Var_t vars[MAX_VARS];
                                                          
                                                          /* Ajoute une variable dans la liste */
                                                          void new_var (char *name, double data)
                                                          {
                                                             if (n_vars >= MAX_VARS)
                                                             {
                                                                CALC_ERROR ("Too much vars!");
                                                                return;
                                                             }
                                                             strncpy (vars[n_vars].name, name, MAX_NAME_LEN - 1);
                                                             vars[n_vars].data = data;
                                                             n_vars++;
                                                          }
                                                          
                                                          /* 
                                                              Recherche une variable dans la liste, et renvoit -1
                                                              si elle n'existe pas.
                                                          */
                                                          int search_var (char *name)
                                                          {
                                                             int i;
                                                             for (i = 0; i < n_vars; i++)
                                                             {
                                                                if (!strcmp (vars[i].name, name))
                                                                   return i;
                                                             }
                                                             return -1;
                                                          }
                                                          
                                                          /*
                                                              Met à jour la variable située à l'indice
                                                              id.
                                                          */
                                                          void update_var(int id, double data)
                                                          {
                                                              vars[id].data = data;
                                                          }
                                                          
                                                          /*
                                                              Vérifie si le caractère est un opérateur
                                                          */
                                                          int is_operator (char c)
                                                          {
                                                             if (c == '-' || c == '+' || c == '*' || c == '/' || c == '^')
                                                                return 1;
                                                             return 0;
                                                          }
                                                          
                                                          /*
                                                              Calcule la priorité du caractère, et stock le résultat à l'endroit pointé
                                                              par priority.
                                                          */
                                                          void calc_priority (char c, int *priority)
                                                          {
                                                             if (c == '-' || c == '+')
                                                                *priority = 1;
                                                             else if (c == '*' || c == '/' || c == '^')
                                                                *priority = 2;
                                                          }
                                                          
                                                          /*
                                                              Calcule les piles actuelles.
                                                          */
                                                          void calcul_stack (Stack_t * num, Stack_t * ops)
                                                          {
                                                             char op;
                                                             double n1, n2;
                                                          
                                                             while (stack_size (num) >= 2 && stack_size (ops) >= 1)
                                                             {
                                                                op = pop_stack (ops);
                                                                n1 = pop_stack (num);
                                                                n2 = pop_stack (num);
                                                                switch (op)
                                                                {
                                                                case '+':
                                                                   push_stack (num, n1 + n2);
                                                                   break;
                                                                case '-':
                                                                   push_stack (num, n1 - n2);
                                                                   break;
                                                                case '/':
                                                                   push_stack (num, n1 / n2);
                                                                   break;
                                                                case '*':
                                                                   push_stack (num, n1 * n2);
                                                                   break;
                                                                case '^':
                                                                   push_stack (num, pow(n1, n2));
                                                                   break;   
                                                                case ')':
                                                                   push_stack (num, n2);
                                                                   push_stack (num, n1);
                                                                   return;
                                                                   break;
                                                                }
                                                             }
                                                          }
                                                          
                                                          /*
                                                              Extrait un nombre de la chaine ptr, et fait pointer
                                                              sur le prochain caractère n'étant plus un nombre.
                                                          */
                                                          double extract_number (char **ptr, char *expr)
                                                          {
                                                             while ((isdigit (**ptr) || **ptr == '.') && *ptr >= expr)
                                                                (*ptr)--;
                                                             (*ptr)++;
                                                             return strtod (*ptr, NULL);
                                                          }
                                                          
                                                          /*
                                                              Extrait un mot composé de caractère alphabétiques
                                                              et fait pointer ptr sur le prochain caractère
                                                              n'étant plus un mot.
                                                          */
                                                          void extract_word (char **ptr, char *expr)
                                                          {
                                                             while(isspace(**ptr) && *ptr >= expr)
                                                              (*ptr)--;
                                                              *((*ptr) + 1) = 0;
                                                             while (isalpha (**ptr) && *ptr >= expr)
                                                                (*ptr)--;
                                                             (*ptr)++;
                                                          }
                                                          
                                                          /*
                                                              Traitement des mots trouvés dans l'expression.
                                                          */
                                                          void handle_word (char **ptr, char *expr, Stack_t * num)
                                                          {
                                                             int i;
                                                             extract_word (ptr, expr);
                                                             if ((i = search_var (*ptr)) != -1)
                                                             {
                                                                push_stack (num, vars[i].data);
                                                             }
                                                             else if ((i = search_keyword (*ptr)) != -1)
                                                             {
                                                                keywords[i].callback (num);
                                                             }
                                                             else
                                                             { 
                                                                CALC_ERROR ("Var don't exist!");
                                                             }   
                                                          
                                                          }
                                                          /*
                                                              Extrait une variable (expression du type var = expression)
                                                          */
                                                          void extract_var (char **ptr, char *expr, Stack_t * num)
                                                          {
                                                             double tmp;
                                                             int i;
                                                             
                                                             extract_word (ptr, expr);
                                                             if (search_keyword (*ptr) != -1)
                                                             {
                                                                CALC_ERROR ("You can't use keyword for named a var!");
                                                                return;
                                                             }
                                                             tmp = pop_stack(num);
                                                             if ((i=search_var (*ptr)) != -1)
                                                                 update_var(i, tmp); 
                                                             else
                                                                 new_var(*ptr, tmp);
                                                                 
                                                             push_stack(num, tmp);    
                                                          }
                                                          
                                                          void clean_ops_stack(Stack_t *op)
                                                          {
                                                              int c;
                                                              while(stack_size(op) > 0)
                                                              {
                                                                  c = pop_stack(op);
                                                                  if(c != ')')
                                                                  {
                                                                      CALC_ERROR("Syntax error");
                                                                      break;
                                                                  }
                                                              }
                                                          }
                                                          /*
                                                              Fonction principale de traitement de l'expression
                                                          */
                                                          double calc_expr (char *expr)
                                                          {
                                                             Stack_t ops_stack;
                                                             Stack_t num_stack;
                                                             Stack_t priority_stack;
                                                          
                                                             int last_priority = 0;
                                                             int priority = 0;
                                                             char *ptr = expr + strlen (expr) - 1;
                                                             error = 0;
                                                          
                                                             init_stack (&ops_stack);
                                                             init_stack (&num_stack);
                                                             init_stack (&priority_stack);
                                                          
                                                             do
                                                             {
                                                                calc_priority (*ptr, &priority);
                                                                if (priority < last_priority)
                                                                   calcul_stack (&num_stack, &ops_stack);
                                                          
                                                                if (isdigit (*ptr))
                                                                {
                                                                   push_stack (&num_stack, extract_number (&ptr, expr));
                                                                }
                                                                else if (*ptr == '(')
                                                                {
                                                                   if(stack_size(&priority_stack) <= 0)
                                                                   {
                                                                      CALC_ERROR("Brace miss!");
                                                                      return 0;
                                                                   }
                                                                   calcul_stack (&num_stack, &ops_stack);
                                                                   priority = pop_stack (&priority_stack);
                                                                }
                                                                else if (*ptr == ')')
                                                                {
                                                                   push_stack (&ops_stack, ')');
                                                                   push_stack (&priority_stack, priority);
                                                                }
                                                                else if (is_operator (*ptr))
                                                                {
                                                                   push_stack (&ops_stack, *ptr);
                                                                }
                                                                else if (isalpha (*ptr))
                                                                {
                                                                   handle_word (&ptr, expr, &num_stack);
                                                                }
                                                                else if (*ptr == '=')
                                                                {
                                                                   *(ptr--) = 0;
                                                                   calcul_stack (&num_stack, &ops_stack);
                                                                   extract_var (&ptr, expr, &num_stack);
                                                                }
                                                                else if(!isspace(*ptr))
                                                                {
                                                                   CALC_ERROR ("Syntax error!");
                                                                   return 0;
                                                                }
                                                          
                                                                last_priority = priority;
                                                             }
                                                             while (ptr-- != expr && !error);
                                                          
                                                             calcul_stack (&num_stack, &ops_stack);
                                                          
                                                             if (stack_size (&num_stack) != 1 && !error)
                                                                CALC_ERROR ("Syntax error!");
                                                             
                                                             if(stack_size(&priority_stack) != 0)
                                                               CALC_ERROR ("Brace miss"); 
                                                             
                                                             clean_ops_stack(&ops_stack);
                                                               
                                                             return pop_stack (&num_stack);
                                                          }
                                                          
                                                          void print_prompt (void)
                                                          {
                                                             printf ("\n>>>");
                                                          }
                                                          
                                                          void clean_fgets_buff (char *buff)
                                                          {
                                                             for (; *buff && *buff != '\n'; buff++);
                                                          
                                                             *buff = 0;
                                                          }
                                                          /*  
                                                              Commande affichant toutes les variables.
                                                          */
                                                          void print_all_vars (void)
                                                          {
                                                             int i;
                                                             for (i = 0; i < n_vars; i++)
                                                             {
                                                                printf ("%s = %g\n", vars[i].name, vars[i].data);
                                                             }
                                                          }
                                                          
                                                          /*
                                                              Commandes internes.
                                                              retourne 1 si le buffer est une commande.
                                                          */
                                                          int handle_cmd (char *buffer)
                                                          {
                                                             if (!strcmp (buffer, "q"))
                                                             {
                                                                printf ("Quitting...\n");
                                                                exit (EXIT_SUCCESS);
                                                             }
                                                             else if (!strcmp (buffer, "vars"))
                                                             {
                                                                print_all_vars ();
                                                                return 1;
                                                             }
                                                             else if(!strcmp (buffer, "delete_vars"))
                                                             {
                                                                  n_vars = 0;
                                                                  return 1;
                                                             }
                                                             else if (!strcmp (buffer, "c"))
                                                             {
                                                                  ans = 0;
                                                                  return 1;
                                                             }
                                                             return 0;
                                                          }
                                                          
                                                          int main (void)
                                                          {
                                                             char buffer[512];
                                                             double result;
                                                             printf ("******** Calc **********\n");
                                                             print_prompt ();
                                                             while (fgets (buffer, sizeof (buffer) - 1, stdin) != NULL)
                                                             {
                                                                clean_fgets_buff (buffer);
                                                                if (!handle_cmd (buffer))
                                                                {
                                                                   result = calc_expr (buffer);
                                                                   if (!error)
                                                                   {
                                                                      ans = result;
                                                                      printf ("%g", result);
                                                                   }   
                                                                }
                                                                print_prompt ();
                                                          
                                                             }
                                                             return 0;
                                                          }
                                                          


                                                          Alors :
                                                          -Nouvelle gestion des piles. (J'ai mis des piles statiques, je trouve ça plus clair pour ce genre de programme)
                                                          -Ajout des variables dans le programme. (On ajoute une variable avec var = expression)
                                                          -Quelques mots clefs : sqrt, ans
                                                          -Quelques commandes : c, q, vars (affiche toutes les variables)

                                                          Je n'ai pas beaucoup testé, donc il y a probablement des bugs. Et la gestion des erreurs de l'expression est quasiment inexistante.
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                            2 septembre 2010 à 18:48:22

                                                            J'ai un bug ^^ :

                                                            >>>x = 5
                                                            Syntax error!
                                                            
                                                            >>>x
                                                            Syntax error!
                                                            Syntax error!
                                                            • Partager sur Facebook
                                                            • Partager sur Twitter
                                                              2 septembre 2010 à 18:49:18

                                                              Mon code ne gère pas les espaces :) .

                                                              (Pis les deux "Syntax error!", c'est dût à ma gestion d'erreurs pourrie, mais c'est corrigé depuis mon dernier édit :) )
                                                              • Partager sur Facebook
                                                              • Partager sur Twitter

                                                              zCalc

                                                              × 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.
                                                              • Editeur
                                                              • Markdown