/* Converte un'espressione aritmetica dalla notazione infissa a quella postfissa. Nel caso si incontri un errore viene sollevata un'eccezione. E' basato su un riconoscitore ricorsivo discendente (RiconoscitoreEspressioni.java). Autore: Giovanni Pighizzini - Maggio 2006 */ import lt2.calc.*; import java.io.*; import java.util.Stack; import static lt2.calc.TipoToken.*; public class GeneraPostfissa { private static Token t; //variabile destinata a contenere il riferimento //al prossimo token da esaminare private static Scanner scanner; //riferimento all'analizzatore lessicale public static void main(String[] args) throws IOException { //creazione del canale di input BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); //lettura della stringa da esaminare System.out.print("Espressione? "); String s = in.readLine(); //creazione dell'analizzatore lessicale: la stringa riferita da s //e' vista come file di input scanner = new Scanner(new StringReader(s)); //preleva il primo token t = scanner.getProssimo(); try { espressione(); //alla fine dell'espressione i token dovrebbero essere finiti if (t.getTipo() == FINE) System.out.println(); else throw new EspressioneException("Stringa non aspettata: " + scanner.yytext()); } catch (EspressioneException e) { System.err.println(e.toString()); } } public static void espressione() throws IOException { TipoToken operatore; termine(); //questa chiamata stampa il termine sinistro while ((t.getTipo() == PIU) || (t.getTipo() == MENO)) { operatore = t.getTipo(); //memorizza il segno t = scanner.getProssimo(); System.out.print(" "); // stampa uno spazio di separazione termine(); //questa chiamata stampa il termine destro //stampa il segno if (operatore == PIU) System.out.print(" +"); else System.out.print(" -"); } } public static void termine() throws IOException { TipoToken operatore; fattore(); //questa chiamata stampa il fattore sinistro while ((t.getTipo() == PER) || (t.getTipo() == DIVISO)) { operatore = t.getTipo(); //memorizza il segno t = scanner.getProssimo(); System.out.print(" "); // stampa uno spazio di separazione fattore(); //questa chiamata stampa il fattore destro //stampa il segno if (operatore == PER) System.out.print(" *"); else System.out.print(" /"); } } public static void fattore() throws IOException { Stack unari = new Stack(); while (t.getTipo() == MENO || t.getTipo() == PIU) { unari.push(t.getTipo()); t = scanner.getProssimo(); } if (t.getTipo() == NUMERO) { System.out.print(t.getValore()); t = scanner.getProssimo(); } else if (t.getTipo() == IDENT) { System.out.print(t.getValore()); t = scanner.getProssimo(); } else if (t.getTipo() == TONDA_APERTA) { t = scanner.getProssimo(); espressione(); //stampa l'espressione if (t.getTipo() == TONDA_CHIUSA) t = scanner.getProssimo(); else throw new EspressioneException("Parentesi chiusa attesa"); } else throw new EspressioneException("Stringa non aspettata: " + scanner.yytext()); //stampa gli eventuali segni unari che precedono l'espressione while (!unari.empty()) { if (unari.pop() == PIU) System.out.print("+"); else System.out.print("-"); } } } /* Nota relativa all'implementazione del metodo fattore. E' stato utilizzato uno stack per memorizzare gli operatori unari che si trovano all'inizio del fattore e poi porli nell'albero nella posizione corretta. Si potrebbe fornire una soluzione alternativa che anziche' introdurre uno stack esplicito, ricorra allo stack utilizzato per implementare la ricorsione. A tale scopo occorre modificare lo schema di riconoscimento utilizzato dal metodo, sostituendo il ciclo while iniziale con una ricorsione. Il metodo dovrebbe essere sviluppato tenendo conto che un fattore e' formato da un operatore unario seguito da un fattore (chiamata ricorsiva) oppure da un numero oppure da un'espressione racchiusa tra parentesi. */ /* Esercizio: Riscrivere GeneraPostfissa in modo che, anziche' stampare di volta in volta gli elementi che compongono la notazione postifissa, costruisca una stringa corrispondente a tale notazione e la visualizzi nel metodo main, al termine dell'esame dell'intera espressione. Ognuno dei metodi espressione, termine e fattore dovra' restituire il riferimento all'oggetto di tipo String che rappresenta, in notazione postfissa, la parte di espressione riconosciuta dal metodo. */