package de.fuberlin.projectci.parseTable; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import de.fuberlin.commons.util.EasyComparableObject; import de.fuberlin.projectci.grammar.NonTerminalSymbol; import de.fuberlin.projectci.grammar.TerminalSymbol; /** * Repräsention einer Parsetabelle mit Action- und Goto-Funktionen. * */ public class ParseTable extends EasyComparableObject{ public Map<State, ActionTable> state2ActionTable = new HashMap<State, ParseTable.ActionTable>(); public Map<State, GotoTable> state2GotoTable = new HashMap<State, ParseTable.GotoTable>(); private State initialState; @Override protected Object[] getSignificantFields() { return new Object[]{initialState,state2ActionTable,state2GotoTable}; } /** * * @return Startzustand */ public State getInitialState(){ return initialState; } /** * Liefert die {@link Action} zu einem {@link State} und einem {@link TerminalSymbol} * @param state * @param terminalSymbol * @return */ public Action getAction(State state, TerminalSymbol terminalSymbol) { return getActionTableForState(state).getAction(terminalSymbol); } /** * Liefert den Wert der Goto-Funktion zu einem {@link State} und einem {@link NonTerminalSymbol} * @param s * @param nts * @return */ public Goto getGoto(State s, NonTerminalSymbol nts) { return getGotoTableForState(s).getGoto(nts); } /** Setzt den Startzustand*/ public void setInitialState(State initialState){ this.initialState=initialState; } /** * Liefert den internen {@link ActionTable} für einen {@link State} * @param s * @return */ public ActionTable getActionTableForState(State s){ if (!state2ActionTable.containsKey(s)){ state2ActionTable.put(s, new ActionTable()); } return state2ActionTable.get(s); } /** * Liefert den internen {@link GotoTable} für einen {@link State} * @param s * @return */ public GotoTable getGotoTableForState(State s){ if (!state2GotoTable.containsKey(s)){ state2GotoTable.put(s, new GotoTable()); } return state2GotoTable.get(s); } /** * Mappt ein {@link TerminalSymbol} auf eine {@link Action} * */ public static class ActionTable extends EasyComparableObject{ private static Action ERROR_ACTION=new ErrorAction(); private Map<TerminalSymbol, Action> terminalSymbol2Action= new HashMap<TerminalSymbol, Action>(); @Override protected Object[] getSignificantFields() { return new Object[]{terminalSymbol2Action, getClass()}; } public Action getAction(TerminalSymbol nts) { Action a= terminalSymbol2Action.get(nts); return a!=null?a:ERROR_ACTION; } public void setActionForTerminalSymbol(Action action, TerminalSymbol terminalSymbol){ terminalSymbol2Action.put(terminalSymbol, action); } @Override public String toString() { StringBuffer strBuf=new StringBuffer(); Set<TerminalSymbol> terminalSymbols = terminalSymbol2Action.keySet(); strBuf.append("["); int i=0; for (TerminalSymbol aTerminalSymbol : terminalSymbols) { if (i>0){ strBuf.append(", "); } strBuf.append(aTerminalSymbol); strBuf.append(" → "); strBuf.append(getAction(aTerminalSymbol)); i++; } strBuf.append("]"); return strBuf.toString(); } public List<TerminalSymbol> getAllLegalTerminals() { // Temporäre Liste List<TerminalSymbol> temp = new LinkedList<TerminalSymbol>(); // Alle Terminale holen Set<TerminalSymbol> terminals = terminalSymbol2Action.keySet(); // Über die Terminalsymbole iterieren und prüfen, ob diese wirklich erlaubt sind for(TerminalSymbol t : terminals) { Action a = terminalSymbol2Action.get(t); if(a != null && !(a instanceof ErrorAction)) { temp.add(t); } } return temp; } } /** * * Mappt ein {@link NonTerminalSymbol} auf ein {@link Goto} * */ public static class GotoTable extends EasyComparableObject{ private Map<NonTerminalSymbol, Goto> nonTerminalSymbol2Goto= new HashMap<NonTerminalSymbol, Goto>(); @Override protected Object[] getSignificantFields() { return new Object[]{nonTerminalSymbol2Goto, getClass()}; } public Goto getGoto(NonTerminalSymbol nonTerminalSymbol){ return nonTerminalSymbol2Goto.get(nonTerminalSymbol); } public void setGotoForNonTerminalSymbol(Goto _goto, NonTerminalSymbol nonTerminalSymbol){ nonTerminalSymbol2Goto.put(nonTerminalSymbol, _goto); } @Override public String toString() { StringBuffer strBuf=new StringBuffer(); Set<NonTerminalSymbol> nonTerminalSymbols = nonTerminalSymbol2Goto.keySet(); strBuf.append("["); int i=0; for (NonTerminalSymbol aNonTerminalSymbol : nonTerminalSymbols) { if (i>0){ strBuf.append(", "); } strBuf.append(aNonTerminalSymbol); strBuf.append(" → "); strBuf.append(getGoto(aNonTerminalSymbol).getTargetState().getId()); i++; } strBuf.append("]"); return strBuf.toString(); } } @Override public String toString() { StringBuffer strBuf=new StringBuffer(); // Annahme: Es gibt keinen State zu dem es ein Goto aber keine Action gibt Set<State> states = sortedStates(); for (State aState : states) { strBuf.append(aState); strBuf.append(": "); strBuf.append(getActionTableForState(aState)); strBuf.append(" "); strBuf.append(getGotoTableForState(aState)); strBuf.append("\n"); } return strBuf.toString(); } /** Zum Sortieren der States nach ihrer ID. */ private static Comparator<State> StateComparator=new Comparator<State>() { @Override public int compare(State s1, State s2) { return s1.getId()-s2.getId(); } }; /** Liefert ein {@link SortedSet} der States.*/ SortedSet<State> sortedStates(){ SortedSet<State> result=new TreeSet<State>(StateComparator); result.addAll(state2ActionTable.keySet()); return result; } }