/* Calcolatrice per espressioni aritmetiche in notazione infissa. Nel caso si incontri un errore viene sollevata un'eccezione. E' basata su un riconoscitore a discesa ricorsiva (Riconoscitore.java). I metodi di riconoscimento e calcolo restituiscono un valore int corrispondente al valore della sottoespressione riconosciuta. (Non sono ammessi gli identificatori) Autore: Giovanni Pighizzini - Maggio 2015 */ import lt.calc.*; import java.io.*; 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 Calcolatrice { 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 { int risultato = espressione(); //alla fine dell'espressione i token dovrebbero essere finiti if (t.getTipo() == EOF) System.out.println("Risultato = " + risultato); else throw new EspressioneException("Stringa non aspettata: " + scanner.yytext()); } catch (EspressioneException e) { System.err.println(e.toString()); } } private static int espressione() throws IOException { int valoreSx = termine(); //calcola il termine sinistro while (t.getTipo() == PIU || t.getTipo() == MENO) { TipoToken operatore = t.getTipo(); //memorizza il segno t = scanner.getNext(); int valoreDx = termine(); //calcola il termine destro //calcola il risultato, utilizzabile nuovamente come termine sinistro valoreSx = operatore == PIU ? valoreSx + valoreDx: valoreSx - valoreDx; } return valoreSx; } private static int termine() throws IOException { int valoreSx = fattore(); //calcola il fattore sinistro while (t.getTipo() == PER || t.getTipo() == DIVISO) { TipoToken operatore = t.getTipo(); //memorizza il segno t = scanner.getNext(); int valoreDx = fattore(); //calcola il fattore destro //calcola il risultato, utilizzabile nuovamente come fattore sinistro valoreSx = operatore == PER ? valoreSx * valoreDx: valoreSx / valoreDx; } return valoreSx; } private static int fattore() throws IOException { int valore; boolean negativo = false; //segno del risultato while (t.getTipo() == MENO || t.getTipo() == PIU) { if (t.getTipo() == MENO) negativo = !negativo; t = scanner.getNext(); } if (t.getTipo() == NUMERO) { valore = t.getInteger(); t = scanner.getNext(); /* } else if (t.getTipo() == IDENT) { *** NO IDENTIFICATORI *** t = scanner.getNext(); */ } else if (t.getTipo() == TONDA_APERTA) { t = scanner.getNext(); valore = 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()); //restituisce il risultato con il segno appropriato return negativo ? -valore : valore; } } /* Nota: Si potrebbe modificare il main fornendo un messaggio appropriato in caso di divisione per 0, intercettando ArithmeticException */