#include "calc.h"

int main (void){
  float result;

  while (1){
		scanf("%s", calc_buffer);
		AtliktiSkaiciavimus(calc_buffer, &result, DEG);
		printf("%s%f", calc_buffer, result);
  }

  return 0;
}

/* 
   ============================================================
      Naujo ir patogesnio skaiciavinmo algoritmo realizacija
   ============================================================

   AtliktiSkaiciavimus() - pagrindine  sio  algoritmo  funkcija.
   char *data - pointeris i stringa su  duomenimis, kuriu rezul-
   tata reikia rasti. Stringas su NULL  terminatorium, pries ku-
   ri turi buti zenklas '='.

				       Pvz: "2*3+4="

   Algoritmo ideja  buvo paimta  is Antano  Vidziuno  knygos
   "C++ ir C++ Builder pradmenys", nes mano sugalvotas algo-
   ritmas veike nepalyginamai prasciau ir reikalavo  daugiau
   man brangios uC atminties. Algoritmo realizacija yra para-
   syta mano paties del dvieju priezasciu:
    1. Knygoje pateikta realizacija  gali naudoti tik 8 bitu
	   sveikuosius skaicius (char), atlieka tik pgr. aritm.
	   veiksmus ir skaiciavimus su skliaustais;
    2. Norejosi geriau susipazinti su siuo algoritmu, todel
	   nesinorejo ziureti i jau esancia realizacija, o pa-
	   bandyti sukurti savo paties.

                    ALGORITMO APRASYMAS

	1. Parengiami du tusti stekai: veiksmu simboliu ID (sop)
	   ir skaiciu arba argumentu (snum);
	2. Nuo string'o pradzios skaitomas veiksmo simbolis arba
	   skaicius;
    3. Jei perskaitomas skaicius, jis rasomas i skaiciu ste-
	   ka snum;
    4. Jei perskaitomas veiksmo simbolis, analizuojamas veis-
	   mu stekas sop. Jei sop tuscias arba jo virsuje esantis
	   simbolis yra  mazesnio  prioriteto, negu perskaitytojo,
	   veiksmo simbolis rasomas i steka sop;
    5. Jei steko sop virsuje esancio simbolio prioritetas yra
	   nemazesnis uz naujai perskaitytojo, simbolis skaitomas
	   is steko ir jo valdomas veiksmas taikomas  dviem (arba
	   vienam) virsutiniam steko snum  skaiciams.  Rezultatas
	   steke snum keicia  ten  buvusius du (arba viena) skai-
	   cius. Veiksmas kartojamas tol, kol sop  tampa  tuscias
	   arba, kol jo virsuje atsiranda simbolis su mazesniu
	   prioritetu uz perskaitytojo. Tada sis simbolis rasomas
	   i steka sop. Uzdarantis skliaustas nerasomas. Jis  tik
	   valdo kitu veiksmu atrinkima is steko sop ir ten esan-
	   cio atidarancio skliausto pasalinima.

																 */

unsigned char AtliktiSkaiciavimus(char *data, float *result, char mode){
	unsigned int x = 0;

	while (data[x]){
		/* Jei skaicius, dedu ji i skaiciu steka */
		if ((data[x] >= '0') && (data[x] <= '9')){
			if (!AddSk(data, &x))
				return BAD_EXPONENT;
		}

		/* Jeigu tai veiksmas, konvertuoju ji i ID (float) ir tada tikrinu jo prioritetus */
		else{
			float steke = 0, cur;

			/* Gaunu is steko skaiciu ir palieku ji ten */
			if (sop)
				steke = sop->data;

			/* Konvertavimas i ID (float) */
			switch(data[x]){
				case '=': cur = LYGU; break;
				case '(': cur = SKLIAUSTAI_ATSIDARO; break;
				case ')': cur = SKLIAUSTAI_UZSIDARO; break;
				case '+': cur = SUDETIS; break;
				case '-':
					/* Manau, kad skaiciaus neigimas gali buti tik pradzioje (x = 0) ir po SKLIAUSTAI_ATSIDARO */
					if (x == 0)						
						cur = NEIGIMAS;
					else if (data[x - 1] == '(')
						cur = NEIGIMAS;
					/* Iprasta atimtis (visi kiti atvejai) */
					else
						cur = ATIMTIS;
					break;
				case '*': cur = DAUGYBA; break;
				case '/': cur = DALYBA; break;
				case '^': cur = LAIPSNIU; break;
				case 'v': cur = SAKNIS; break;
				default:
					{
						/* MATH.H funkcijos, kurios aprasomos daugiau negu 1 simboliu. */
						if (!memcmp(&data[x], "sin", 3)){
							cur = SIN;
							x += 2;
						}
						else if (!memcmp(&data[x], "cos", 3)){
							cur = COS;
							x += 2;
						}
						else if (!memcmp(&data[x], "tan", 3)){
							cur = TAN;
							x += 2;
						}
						else if (!memcmp(&data[x], "log", 3)){
							cur = LOG;
							x += 2;
						}
						else if (!memcmp(&data[x], "asin", 4)){
							cur = ASIN;
							x += 3;
						}
						else if (!memcmp(&data[x], "acos", 4)){
							cur = ACOS;
							x += 3;
						}
						else if (!memcmp(&data[x], "atan", 4)){
							cur = ATAN;
							x += 3;
						}
						else if (!memcmp(&data[x], "lg", 2)){
							cur = LOG;
							x += 1;
						}

						/* Jei neteisinga (nesuprantama) salyga. */
						else
							return INCORRECT_EXPRESSION;
					}
			}

			/* Zemiausiu prioritetu salyga */ 
			if (cur <= SKLIAUSTAI_UZSIDARO){
				if(((sop == NULL)||(cur == SKLIAUSTAI_ATSIDARO))&&(cur!=SKLIAUSTAI_UZSIDARO))
					push(&sop, cur);
				else{
					while (sop != NULL){
						if (sop){
							steke = sop->data;
							if(sop->data == SKLIAUSTAI_ATSIDARO){
								pop(&sop);
								break;
							}
						}
						Skaiciuoti(mode);
					}
				}
			}

			/* Vidutiniu prioritetu salyga */
			else if ((cur >= SUDETIS) && (cur <= ATIMTIS)){
				/* Steke esancios operacijos prioritetas yra nemazesnis */
				while ((steke >= SUDETIS)&&(sop != NULL)){
					Skaiciuoti(mode);
					if (sop)
						steke = sop->data;
				}
				push(&sop, cur);
			}
 
			/* Aukstesniuju prioritetu salyga */
			else if ((cur >= DAUGYBA) && (cur < NEIGIMAS)){
				/* Jei prioritetai lygus */
				while ((steke >= DAUGYBA)&&(sop != NULL)){
					Skaiciuoti(mode);
					if (sop)
						steke = sop->data;
				}

				/* Jei prioritetas operacijos, esancios steke, yra mazesnis uz dabar nuskaitytaji */
				push (&sop, cur);
			}

			/* Auksciausiuju prioritetu salyga */
			else{
				while ((steke >= NEIGIMAS) && (sop != NULL)){
					Skaiciuoti(mode);
					if (sop)
						steke = sop->data;

				}
				
				push(&sop, cur);
			}

		}
		x++;
	}

	*result = pop(&snum);
	return TRUE;
}

/* Ideti skaiciu (argumenta) i skaiciu steka (snum) */
BOOL AddSk(char *data, unsigned int *x){
	unsigned int prad, pab;
	char tmp;
	float skaicius;
	BOOL dot_found = FALSE;
	//Leisti: ['0' - '9'], "e+/-", '.'
	pab = prad = *x;

	/* Ieskau skaiciaus pabaigos */
	while (((data[pab] >= '0') && (data[pab] <= '9')) || (data[pab] == '.') || (data[pab] == 'e')){
		/* Exponente? */
		if(data[pab] == 'e'){
			if ((data[pab+1] == '+') || (data[pab+1] == '-')){
				pab++;

				/* Klaidinga informacija (neteisinga eksponente) */
				if (!((data[pab + 1] >= '0') && (data[pab + 1] <= '9')))
					return FALSE;
			}
			
			/* Klaidinga informacija (neteisinga eksponente) */
			else return FALSE;
		}

		/* Toliau ieskoma skaiciaus pabaigos */
		pab++;

		/* Taskas negali kartotis. Gali buti panaudotas tik 1 karta */
		if(data[pab - 1] == '.'){
			if (dot_found) break;
			else dot_found == TRUE;
		}
	}

	/* Konvertuoju gauta skaiciu i float */
	tmp = data[pab];
	data[pab] = 0;
	skaicius = atof(&data[prad]);
	data[pab] = tmp;

	/* Dedu ji i steka */
	push(&snum, skaicius);

	*x = pab-1;
	return TRUE;
}

/* Atlikti steke nurodyta veiksma su virsuje esanciais skaiciais */
void Skaiciuoti(unsigned char mode){
	/* Vienas laipsnis lygus tiek radianu */
	const float degrad = 0.017453292520; 

	float a = 0, b, veiksmas;
	b = pop(&snum);
	veiksmas = pop(&sop);

	/* Aritmetika */
	if (veiksmas == SUDETIS)       { a = pop(&snum); push(&snum, a + b); }
	else if (veiksmas == ATIMTIS)  { a = pop(&snum); push(&snum, a - b); }
	else if (veiksmas == DAUGYBA)  { a = pop(&snum); push(&snum, a * b); }
	else if (veiksmas == DALYBA)   { a = pop(&snum); push(&snum, a / b); }
	else if (veiksmas == LYGU)     push(&snum, b);
	else if (veiksmas == NEIGIMAS) push(&snum, -b);
	/* Trigonometrija */
	else if (veiksmas == SIN)      push(&snum, (mode == DEG) ? sin(b*degrad) : sin(b));
	else if (veiksmas == COS)      push(&snum, (mode == DEG) ? cos(b*degrad) : cos(b)); 
	else if (veiksmas == TAN)      push(&snum, (mode == DEG) ? tan(b*degrad) : tan(b));
	/* Trigonometrija. Arc funkcijos */
	else if (veiksmas == ASIN)     push(&snum, (mode == DEG) ? asin(b)/degrad : asin(b));
	else if (veiksmas == ACOS)     push(&snum, (mode == DEG) ? acos(b)/degrad : acos(b));
	else if (veiksmas == ATAN)     push(&snum, (mode == DEG) ? atan(b)/degrad : atan(b));
    /* Kitos MATH.H funkcijos */
	else if (veiksmas == LOG)      push(&snum, log10(b));
	else if (veiksmas == LAIPSNIU) { a = pop(&snum); push(&snum, pow(a, b)); }
	else if (veiksmas == SAKNIS)   push(&snum, sqrt(b));
}

/* Darbas su steku, kuri naudoja skaiciavimo algoritmas */
/* push() - raso duomenis i steka 			 			*/
void push (STACK **s, float data){
	STACK *news = malloc(sizeof (STACK));
	news->data = data;
	news->prev = *s;
	*s = news;
}

/* Darbas su steku, kuri naudoja skaiciavimo algoritmas */
/* pop() - isima steko virsuje esanti skaiciu           */
float pop(STACK **s){
	float ret = (*s)->data;
	STACK *prev = (*s)->prev;
	free(*s);
	*s = prev;
	return ret;
}
/*
   ============================================================
          Skaiciavimo algoritmo realizacijos pabaiga
   ============================================================
																 */
//----------------------------[END OF CALC_APP.C]-------------------------------
