class Espressioni{

// Voglio riconoscere espressioni aritmetiche nelle quali:
// >>> compaiano costanti numerali per i numeri 0,1,2,3,..,
//     13,.. , 234,..
// >>> si faccia uso degli operatori diadici +,-,*,/
// >>> si faccia uso della parentesizzazione completa
//     (nel senso che ogni volta che uso uno dei 4 operatori,
//     devo spendermi anche una coppia di parentesi tonde)
// 
// Ignoreremo la presenza di spazi vuoti tranne che
// dentro i numerali
//
// Non mi contentero` di riconoscere le espressioni ben-formate,
// ma vorro` anche il loro valore.

// Esempi:
//        (3* *1) non e` un'espressione
//         3 e` un'espressione (minima)
//        13 e` un'espressione (minima)
//        -3 e` un'espressione (o no?) NO!
//        3+4 e` un'espressione (o no?) NO!
//        (3+4) e` un'espressione
//        ((3+4)-((55*10)*9)) e` un'espressione
//        ((3+4)/(22 -22)) e` un'espressione?


/* DIGRESSIONE (SALTARE!!!):

String a = "alfa", b = "beto";

a += b; // a = a + b;

// La var. a riferisce ora la nuova stringa "alfabeto";
// la vecchia e` rimasta come relitto in memoria,
// in attesa di essere eliminata da un processo
// automatico chiamato garbage collector. 

(FINE DELLA DOGRESSIONE) */

public static Integer esp( String ex ){

    if ( ex == null ) return null; // fatto fiasco
    
    int[] cursore = { 0 };
    
    Integer val = espr( ex, cursore ); // Qui invochiamo il vero lavoratore.

    // Per concludere, dobbiamo sincerarci che non siano
    // rimasti dei caratteri diversi dallo spazio vuoto
    // a partire dalla posizione del cursore in avanti;
    // il che contrasterebbe con le norme grammaticali 
    // che ci siamo dati.

    return ( proxCar( ex, cursore ) == null ) ? val : null ;  
}


private static Integer espr( String e, int[] c ){

// Workhorse: Il motore ricorsivo del procedimento.
//
// Riconosciamo e valutiamo espressioni di due sorte:
// (1) quelle che iniziano con '(' e quelle elementari,
// (2) costituite da cifre decimali consecutive.

Integer a, b; // I due operandi

if ( proxCar( e, c ) == '(' ){ // espressione composta

    c[0]++; // vado oltre la parentesi appena vista
    
    a = espr( e, c ); // 1.o operando: notare la ricorsione
    
    if ( a == null ) return null;
    
    char[] operatori = { '*', '/', '+', '-' };
    
    for( char opt : operatori ) // i 4 possibili operatori
    
       if ( proxCar( e, c ) == opt ){
    
          c[0]++; // vado oltre l'operatore appena individuato
    
          b = espr( e, c ); // 2.o operando: altra ricorsione

          if ( b == null ) return null;
       
          // integro assieme i due operandi

          if ( opt == '/' &&  b == 0 ) return null;
                 
          // a = a opt b; // lo penso ma non lo dico
    
          a = (opt == '+') ? (a+b) :
        
              (opt == '-') ? (a-b) :
        
              (opt == '*') ? (a*b) :
        
                             (a/b) ;
                             
            break;
        }
    
    if ( proxCar( e, c ) != ')' ) return null;
    
    c[0]++;
     
    return a;

} // else

return numerale( e, c ); // espressione atomica: seq. di cifre

}


private static Integer numerale( String ex, int[] c ){

    if (! (c[0] < ex.length()
    
         && ex.charAt( c[0] ) >= '0' && ex.charAt( c[0] ) < '9' ))
    
    		return null;
    
    Integer num = 0; // accumulatore del risultato numerico
    
    do{
         
         num = num * 10 + (ex.charAt( c[0] ) - '0');
         
         c[0]++;
    
    }  while( c[0] < ex.length()
    
         && ex.charAt( c[0] ) >= '0' && ex.charAt( c[0] ) < '9' );
    
    return num;
}
    


private static Character proxCar( String ex, int[] c ){

// Spazzola ex a partire dalla posizione indicata dal cursore c
// fino ad imbatterti in un carattere non-blank. Restituisci
// quest'ultimo (se c'e`).

    while( c[0] < ex.length() && ex.charAt( c[0] ) == ' ' )

        c[ 0 ]++; // il cursore avanza
        
    return (c[0] >= ex.length()) ? null : ex.charAt( c[0] );
} 


    public static void main( String[] aaa ) {
    
// Programma iniziale usa-e-getta, che serve solo al collaudo di questa classe.

        String espress = "(2+2)";
        
        do {
        
             System.out.println( espress+" == "+ esp( espress) );

             espress = Leggi.leggi( "espressione" );
        }
        while ( espress != null );
    }
}