#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef struct _fraction {
   int num;
   int den;
} fraction;

void print(fraction frac) {
   printf(" %d/%d ",frac.num,frac.den); 
}

int pgcd(int n,int m) {
   assert(n > 0 && m > 0);
   int tmp_n = n,tmp_m = m;
   while (tmp_n%tmp_m > 0) {
      int tmp = tmp_n;
      tmp_n = tmp_m;
      tmp_m = tmp%tmp_m;
   }
   return tmp_m;
}

void reduire(fraction* frac) {
   if (0 == frac->num) { 
      frac->den = 1;
   } else {
      int gcd = pgcd(abs(frac->num),frac->den);
      frac->num /= gcd;
      frac->den /= gcd;
   }
}

fraction fraction_build(int num,int den) {
   assert(den != 0);
   int sign = den/abs(den);
   fraction res = {sign*num,sign*den};
   reduire(&res);
   return res;
}

fraction add(fraction frac1,fraction frac2) {
   return fraction_build(frac1.num*frac2.den+frac1.den*frac2.num,frac1.den*frac2.den);
}

fraction add1(int n,fraction frac) {
   return add(fraction_build(n,1),frac);
}

fraction add2(fraction frac,int n,) {
   return add1(n,frac);
}

void add_inplace(fraction* frac1,fraction frac2) {
   *frac1 = add(*frac1,frac2);
}

fraction sub(fraction frac1,fraction frac2) {
   return add(frac1,fraction_build(-frac2.num,frac2.den));
}

fraction sub1(int n,fraction frac) {
   return sub(fraction_build(n,1),frac);
}

fraction sub2(fraction frac,int n,) {
   return add(frac,-n);
}

void sub_inplace(fraction* frac1,fraction frac2) {
   *frac1 = sub(*frac1,frac2);
}

fraction mult(fraction frac1,fraction frac2) {
   return fraction_build(frac1.num*frac2.num,frac1.den*frac2.den);;
}

fraction mult1(int n,fraction frac) {
   return mult(frac,fraction_build(n,1));
}

fraction mult2(fraction frac,int n) {
   return mult1(n,frac);
}

void mult_inplace(fraction* frac1,fraction frac2) {
   *frac1 = mult(*frac1,frac2);
}

fraction divide(fraction frac1,fraction frac2) {
   assert(frac2.num != 0);
   int sign = frac2.num/abs(frac2.num);
   return mult(frac1,fraction_build(sign*frac2.den,abs(frac2.num)));
}

fraction div1(int n,fraction frac) {
   return divide(fraction_build(n,1),frac);
}

fraction div2(fraction frac,int n) {
   return divide(frac,fraction_build(n,1));
}

void divide_inplace(fraction* frac1,fraction frac2) {
   *frac1 = divide(*frac1,frac2);
}

fraction puiss(fraction frac,int n) {
   fraction prod = fraction_build(1,1); 
   for (int i=1;i<=abs(n);i++) {
      prod = mult(prod,frac);
   }
   if (n < 0) {
      prod = div1(1,prod);
   }
   return prod;
}

float reel(fraction frac) {
   return (float)frac.num/(float)frac.den;
}

fraction compute(fraction f1,fraction f2,char op) {     
   fraction res;
   switch(op) {
      case 'x': res = mult(f1,f2);      break;     
      case '+': res = add(f1,f2);       break;       
      case '/': res = divide(f1,f2);    break;      
      case '-': res = sub(f1,f2);       break;
      case 'p': res = puiss(f1,f2.num); break;
      default : printf("Pas implémenté\n");
   }
   return res;
}
  
void main(int argc,char** argv) {
   fraction f1,f2;
   switch(argc) {
      case 3:
         printf("%d\n",pgcd(atoi(argv[1]),atoi(argv[2])));
         break;
      case 5:
         // teste si le 2ème argument est un dénominateur (donc > 0)
         if ('1' <= argv[2][0] && argv[2][0] <= '9') {
            f1 = fraction_build(atoi(argv[1]),atoi(argv[2]));
            f2 = fraction_build(atoi(argv[4]),1);
            print(compute(f1,f2,argv[3][0]));
         } else {
            f1 = fraction_build(atoi(argv[1]),1);
            f2 = fraction_build(atoi(argv[3]),atoi(argv[4]));
            print(compute(f1,f2,argv[2][0]));
         }
         break;
      case 6:
         f1 = fraction_build(atoi(argv[1]),atoi(argv[2]));
         print(f1); printf("\n");
         f2 = fraction_build(atoi(argv[4]),atoi(argv[5]));
         print(f2); printf("\n");
         print(compute(f1,f2,argv[3][0]));
         break;
      default: printf("Pas implémenté\n");
   }
   printf("\n");
}