package Wider; import java.io.IOException; /** * Rekursiv absteigender Parser für den Eingabestring, * benutzt die Klassen Scanner zum einlesen eines Tokens und * Calculator zum Berechnen der Werte. * Folgende einfache Grammatik (EBNF) wird zum Parsen verwendet: * * network ::= <resistor> [ { "+" <resistor> } | { "/" <resistor> } ] * resistor ::= ( "(" <network> ")" ) | <integer> * * @see Scanner * @see Calculator */ public class Parser implements Tokens { int token; int resistorcount = 0; Scanner scanner = null; Calculator calcer = null; /** * Initialisiert Parser mit Eingabestring, der zu Parsen ist. */ public Parser(String in) throws IOException, WiderException { scanner = new Scanner(in); calcer = new Calculator(); token = scanner.getToken(); } /** * liefert den Rückgabewert des gesamten Ausdrucks. * @return Widerstandswert des gesamten Netzwerk */ public double calc() throws Exception { double tmp = network(); if (resistorcount > 15) throw new WiderException("too many resistors"); if (token != EOF) throw new WiderException("unexpected token"); return tmp; } /** * entspricht <network> in der Grammatik: * berechnet ein einfaches Netzwerk bestehend aus Widerstandswert und Operatoren * * @see resistor * * @return Widerstandswert des Netzwerkes, bzw. einer Ebene des Netzwerkes */ double network() throws Exception { double ret = 0.0; double[] tmp = new double[15]; int count = 0; tmp[0] = resistor(); if (token == PLUS) { while (token == PLUS) { token = scanner.getToken(); tmp[++count] = resistor(); if (tmp[count] == 0) throw new WiderException("resistor must be greater than zero"); if (count > 15) throw new WiderException("too many resistors"); } ret = calcer.calc(tmp, PLUS); } else if (token == SLASH) { while (token == SLASH) { token = scanner.getToken(); tmp[++count] = resistor(); if (count > 15) throw new WiderException("too many resistors"); } ret = calcer.calc(tmp, SLASH); } else if ((token == EOF) || (token == RPAREN)) { ret = tmp[0]; } else throw new WiderException("syntax error"); return ret; } /** * Berechnet einen Widerstandswert, der entweder aus einem int besteht, oder * in Klammern steht. Tritt eine Klammer auf, wird ihr Inhalt wieder mit * network() geparst. * * @see network * * @return Widerstandswert eines einzelnen Widerstands bzw. einer Klammerebene */ double resistor() throws Exception { if (token == INT) { token = scanner.getToken(); resistorcount++; return scanner.getValue(); } else if (token == LPAREN) { token = scanner.getToken(); double tmp = network(); if (token != RPAREN) throw new WiderException("klammer nicht geschlossen"); token = scanner.getToken(); return tmp; } else throw new WiderException("unexpected token"); } }