/*
MODYFIKACJA: teraz używamy wskaźników na funkcje
Podstawowe operacji na ułamkach.
Program prosi o podanie wyrazu z udziałem ułamków (tylko + - * /),
sprowadza podane wyrażenie do jednego ułamku.
np: po wprowadzeniu wyrażenia: 2/6+1/6
program wypisuje: 1/3+1/6=1/2
struktury, przekazywanie struktur do funkcji
cin.clear(ios::badbit);
instrukcja sterująca switch(...) { case: break; default: }















*/
#include <iostream>
#include <limits>

using namespace std; // w starszych kompilatorach trzeba zakomentować ten wiersz

struct Ulamek { int Licznik,Mianownik; };

long NWD(long a,long b);

void Drukuj(const Ulamek &U) { cout<<U.Licznik<<'/'<<U.Mianownik; }

Ulamek ULAMEK(long Licznik,long Mianownik)
  {
   Ulamek U;
   U.Licznik=Licznik;
   U.Mianownik=Mianownik;
   return(U);
  }

Ulamek Skroc(long Licznik,long Mianownik)
  {
   int n=NWD(Licznik,Mianownik);
   if((n<0)^(Mianownik<0)) n=-n; // aby mianownik był zawsze dodatni
   return(ULAMEK(Licznik/n,Mianownik/n));
  }

Ulamek Wprowadz()
  {
   long Licznik,Mianownik;
   char Lamana;
   cin>>Licznik>>Lamana>>Mianownik;
   if((cin)&&(Lamana!='/')) cin.clear(ios::badbit);
   return(Skroc(Licznik,Mianownik));
  }

Ulamek Dodaj(const Ulamek &A,const Ulamek &B)
  {
   return(Skroc(A.Licznik*B.Mianownik+B.Licznik*A.Mianownik,A.Mianownik*B.Mianownik));
  }

Ulamek Odejmij(const Ulamek &A,const Ulamek &B)
  {
   return(Skroc(A.Licznik*B.Mianownik-B.Licznik*A.Mianownik,A.Mianownik*B.Mianownik));
  }

Ulamek Mnoz(const Ulamek &A,const Ulamek &B)
  {
   return(Skroc(A.Licznik*B.Licznik,A.Mianownik*B.Mianownik));
  }

Ulamek Dziel(const Ulamek &A,const Ulamek &B)
  {
   return(Skroc(A.Licznik*B.Mianownik,A.Mianownik*B.Licznik));
  }

//typedef Ulamek OperacjaUlamkowa(const Ulamek&,const Ulamek&);
//struct
//  {
//   char Znak;
//   OperacjaUlamkowa *Operacja;
//  }
// ...
struct
  {
   char Znak;
   Ulamek (*Operacja)(const Ulamek&,const Ulamek&); // wskaźnik do funkcji
  }
  Op[]=
  {
    {'+',Dodaj},
    {'-',Odejmij},
    {'*',Mnoz},
    {':',Dziel}
  };
const OpRozmiar=sizeof(Op)/sizeof(*Op);

int main()
  {
   while(true)
     {
      cout<<"Podaj wyraz ulamkowy (!-koniec): ";
      Ulamek A,B;
      char Operacja;
      A=Wprowadz();
      cin>>Operacja;
      B=Wprowadz();
      if(cin)
        {
         Ulamek U;
         int i;
         for(i=0;i<OpRozmiar;++i)
           {
            if(Op[i].Znak==Operacja)
              {
               U=Op[i].Operacja(A,B); // wywolanie przez wskaźnik
               Drukuj(A);
               cout<<Operacja;
               Drukuj(B);
               cout<<'=';
               Drukuj(U);
               cout<<endl;
               break;
              }
           }
         if(i>=OpRozmiar)
           {
            cout<<"Dozwolone operacje to:";
            for(i=0;i<OpRozmiar;++i) cout<<' '<<Op[i].Znak;
            cout<<endl;
           }
        }
      else
        {
         cin.clear();
         if(cin.get()=='!') break;
         cout<<"Blad wprowadzenia"<<endl;
        }
      cin.ignore(INT_MAX,'\n');
      cout<<endl;
     }
   return 0;
  }

long NWD(long a,long b)
  {
   if(a)
     {
      if(!b) return(a);
      while(b) { int r=a%b; a=b; b=r; }
      return(a);
     }
   return(b?b:1);
  }


