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 ); } }