#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TOKENS 9

typedef struct cella* t_albero;

struct cella{
    char* info;
    t_albero op1;
    t_albero op2;
};


struct token {
   char operatore[10];
   int arieta;
};

struct token tokens[]={
	{"+",2},
	{"-",2},
	{"~",1},
	{"*",2},
	{"/",2},
	{"^",2},
	{"sin",1},
	{"cos",1},
	{"log",1},
	{"exp",1}
};


/*estrae il prossimo token*/
char* prossimo_token(char* token, char* espressione) {
   while (*espressione != ' ' && *espressione != '\0') {
      *token = *espressione;
      token++;
      espressione++;
   }
   *token = '\0';
   while (*espressione == ' ' && *espressione != '\0')
      espressione++;
   return espressione;
}


/*Restituisce l'arieta di un operatore. Se non si trova nella tabella
 * restituisce 0*/
int arieta(char* str) {
   int i;
   int risultato = 0;
   for (i=0; i < TOKENS; i++)
      if (!strcmp(str, tokens[i].operatore))
         risultato = tokens[i].arieta;
   return risultato;
}


/*costruisce l'albero a partire dalla stringa*/
char* build(t_albero* res, char* espressione) {
   char token[100];
   if (*espressione) {
      espressione = prossimo_token(token, espressione);
      switch (arieta(token)) {
      case 0:   /*caso di costante numerica o variabile*/
	      *res = malloc(sizeof(struct cella));
	      (*res)->info = malloc(strlen(token)+1);
	      strcpy((*res)->info, token);
	      (*res)->op1 = NULL;
	      (*res)->op2 = NULL;
	      break;
      case 1: /*caso di operatore con arieta 1*/
	      *res = malloc(sizeof(struct cella));
	      (*res)->info = malloc(strlen(token)+1);
	      strcpy((*res)->info, token);
	      espressione = build(&((*res)->op1), espressione);
	      (*res)->op2 = NULL;
              break;
      case 2: /*caso di operatore con arieta 1*/
	      *res = malloc(sizeof(struct cella));
	      (*res)->info = malloc(strlen(token)+1);
	      strcpy((*res)->info, token);
	      espressione = build(&((*res)->op1), espressione);
	      espressione = build(&((*res)->op2), espressione);
      }
   }
   return espressione;
}


t_albero distruggi_albero(t_albero albero){
   if (albero) {
      albero->op1 = distruggi_albero(albero->op1);
      albero->op2 = distruggi_albero(albero->op2);
      free(albero->info);
      free(albero);
   }
   return NULL;
}


void stampa_albero(t_albero a) {
	if (a) {
		printf("%s ", a->info);
		stampa_albero(a->op1);
		stampa_albero(a->op2);
	}
}

/*Introdurre la gestione dell'errore!*/
int main(){
   int i;
   char espressione[]="+ 5 * 2 sin alfa";
   t_albero albero;
   char *pc = build(&albero, espressione);
   if (*pc) {
      printf("Errore nel parsing della stringa");
   }
   stampa_albero(albero);
   albero = distruggi_albero(albero);
   return 0;
}

