/* 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 a discesa ricorsiva (Riconoscitore.java). Autore: Giovanni Pighizzini - Maggio 2015 */ import lt.calc.*; import java.io.*; import java.util.Stack; import static lt.calc.TipoToken.*; //importazione delle costanti //permette di evitare di specificare il nome della classe TipoToken //davanti ai nomi delle costanti come PIU, MENO, ecc. 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 stream di input scanner = new Scanner(new StringReader(s)); //preleva il primo token t = scanner.getNext(); try { espressione(); //alla fine dell'espressione i token dovrebbero essere finiti if (t.getTipo() == EOF) System.out.println(); else throw new EspressioneException("Stringa non aspettata: " + scanner.yytext()); } catch (EspressioneException e) { System.err.println(e.toString()); } } private static void espressione() throws IOException { termine(); //stampa termine sinistro while (t.getTipo() == PIU || t.getTipo() == MENO) { TipoToken operatore = t.getTipo(); //memorizza il segno t = scanner.getNext(); termine(); //stampa termine destro //stampa il segno if (operatore == PIU) System.out.print("+ "); else System.out.print("- "); } } private static void termine() throws IOException { fattore(); //stampa fattore sinistro while (t.getTipo() == PER || t.getTipo() == DIVISO) { TipoToken operatore = t.getTipo(); //memorizza il segno t = scanner.getNext(); fattore(); //stampa fattore destro //stampa il segno if (operatore == PER) System.out.print("* "); else System.out.print("/ "); } } private static void fattore() throws IOException { Stack unari = new Stack(); while (t.getTipo() == MENO || t.getTipo() == PIU) { unari.push(t.getTipo()); t = scanner.getNext(); } if (t.getTipo() == NUMERO) { System.out.print(t.getInteger() + " "); t = scanner.getNext(); } else if (t.getTipo() == IDENT) { System.out.print(t.getString() + " "); t = scanner.getNext(); } else if (t.getTipo() == TONDA_APERTA) { t = scanner.getNext(); espressione(); if (t.getTipo() == TONDA_CHIUSA) t = scanner.getNext(); 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("u+ "); //prefisso 'u' indica unario else System.out.print("u- "); } } } /* 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, 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. */