/* Esamina un'espressione aritmetica proveniente da un analizzatore lessicale e costruisce un Abstract Syntax Tree che la rappresenta. In questa versione viene utilizzata una symbol table per memorizzare gli identificatori. Autore: Giovanni Pighizzini - Maggio 2006 - Aggiornamento: maggio 2014 */ import lt2.calc.*; import java.io.*; import java.util.Stack; import static lt2.calc.TipoToken.*; public class ParserEspressioni { private Token t; //variabile destinata a contenere il riferimento //al prossimo token da esaminare private Scanner scanner; //riferimento all'analizzatore lessicale private SymbolTable symbolTable; //symbol table utilizzata dal parser /* Crea il parser, associandogli l'analizzatore lessicale specificato tramite l'argomento */ public ParserEspressioni(Scanner sc) { scanner = sc; symbolTable = new SymbolTable(); //symbol table vuota } /* Metodo di parsing: restituisce la radice dell'albero corrispondente all'espressione riconosciuta. Solleva una IOException nel caso vi sia un problema nella lettura, solleva una EspressioneException nel caso l'espressione non sia sintatticamente corretta. */ public Expr parse() throws IOException { t = scanner.getProssimo(); //preleva primo token Expr e = espressione(); //costruzione dell'albero //alla fine dell'espressione i token dovrebbero essere finiti if (t.getTipo() == FINE) return e; //restituisce il riferimento all'albero else throw new EspressioneException("Stringa non aspettata: " + scanner.yytext()); } /* Questo metodo restituisce la symbol table costruita */ public SymbolTable getSymbolTable() { return symbolTable; } private Expr espressione() throws IOException { TipoToken operatore; Expr alberoSx, alberoDx; alberoSx = termine(); //costruisce il sottoalbero sinistro while ((t.getTipo() == PIU) || (t.getTipo() == MENO)) { operatore = t.getTipo(); //memorizza il segno t = scanner.getProssimo(); alberoDx = termine(); //costruisce il sottoalbero destro //crea un nuovo albero contenente i due sottoalberi sx e dx if (operatore == PIU) alberoSx = new PiuExpr(alberoSx, alberoDx); else alberoSx = new MenoExpr(alberoSx, alberoDx); } return alberoSx; } private Expr termine() throws IOException { TipoToken operatore; Expr alberoSx, alberoDx; alberoSx = fattore(); //costruisce il sottoalbero sinistro while ((t.getTipo() == PER) || (t.getTipo() == DIVISO)) { operatore = t.getTipo(); //memorizza il segno t = scanner.getProssimo(); alberoDx = fattore(); //costruisce il sottoalbero destro //crea un nuovo albero contenente i due sottoalberi sx e dx if (operatore == PER) alberoSx = new PerExpr(alberoSx, alberoDx); else alberoSx = new DivisoExpr(alberoSx, alberoDx); } return alberoSx; } private Expr fattore() throws IOException { Expr albero; Stack unari = new Stack(); while (t.getTipo() == MENO || t.getTipo() == PIU) { unari.push(t.getTipo()); t = scanner.getProssimo(); } if (t.getTipo() == NUMERO) { albero = new NumExpr((Integer) t.getInteger()); t = scanner.getProssimo(); } else if (t.getTipo() == IDENT) { String ident = t.getString(); Descrittore d = symbolTable.trovaEAggiungi(ident); albero = new IdExpr(d); t = scanner.getProssimo(); } else if (t.getTipo() == TONDA_APERTA) { t = scanner.getProssimo(); albero = 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()); while (!unari.empty()) { if (unari.pop() == PIU) albero = new UnPiuExpr(albero); else albero = new UnMenoExpr(albero); } return albero; } }