import eprog.*; import java.util.*; /** * <tt>WidParser</tt><br> * WidParser liefert mir den Wert des WiderstandNetzes. * * @see FLAGS * @see Widerst */ class WidParser extends EprogIO { private double fWiderstand; private boolean bParseError; //Konstanten für den Parser private final char SEQUENCEOPEN = '('; private final char SEQUENCECLOSE = ')'; private final char LIMITER = ','; //laut Spez dürfens nicht mehr als 6 Stück sein... ;( private final int EPROG_LIMIT = 6; //ein Counter um das auch zu überwachen... private int iEprogCount = 0; /** * <tt>WidParser</tt><br> * Constructor; nimmt den Eingabestring entgegen und parsed ihn. */ WidParser(String sInputString) { bParseError = false; fWiderstand = parseString(sInputString); } /** * <tt>getWiderstand()</tt> * @return double */ public double getWiderstand() { return fWiderstand; } /** * <tt>getError()</tt><br> * @return boolean */ public boolean getError() { return bParseError; } /** * <tt>parseString</tt><br> * rekursiver Parser der das WiderstandsNetz auswertet. * @return double */ private double parseString(String sWidNet) { Vector vWidValues = new Vector(); double result= 0.0; char cOP = 'x'; int iSkip= 0; //String muss mit "(" beginnen und mit ")" enden. if(sWidNet.charAt(0) == SEQUENCEOPEN && sWidNet.charAt(sWidNet.length()-1) == SEQUENCECLOSE) { //er tut es, und wir kürzen die Klammer weg... sWidNet = sWidNet.substring(1,sWidNet.length()-1); if(FLAGS.DEBUG) println("in 'parseString()': value of string at start:\t" + sWidNet); //Schleife arbeitet sich durch den ganzen String durch. for(int i=0;;i++) { //Hoppala, wir haben einen Unterausdruck anstelle von //Widerstandswert. Also extrahieren wir den Unterausdruck //und geben ihn als Argument rekursiv parseString mit. if(sWidNet.charAt(0)== SEQUENCEOPEN) { String stmp = getSubSequence(sWidNet); iSkip = stmp.length(); vWidValues.add(new Double(parseString(stmp))); } //Wir haben einen WiderstandsWert gefunden. Da es auch //nur ein Symbol sein kann, extrahieren wir es wieder und //geben es der Methode getValue() mit. else { if(++iEprogCount>EPROG_LIMIT){bParseError=true;return 0.0;}; vWidValues.add(new Double(getValue(getSubValue(sWidNet)))); if(((Double)(vWidValues.get(i))).doubleValue() < 1){bParseError= true;return 0.0;} if(FLAGS.DEBUG) println("in 'parseString()': value of current argument:\t" + vWidValues.get(i).toString()); } //Wir schneiden die länge der Subsequenz ab, sWidNet = sWidNet.substring(iSkip,sWidNet.length()); iSkip = 0; //und holen uns den nächsten Ausdruck. sWidNet = sWidNet.substring(sWidNet.indexOf(LIMITER)+1,sWidNet.length()); if(FLAGS.DEBUG) println("in 'parseString()': value for next loop:\t" + sWidNet); //wenn jetzt nichts mehr übrig ist, hat der String einen //Syntaxfehler gehabt. Ansonsten holen wir uns den //nächsten Character und schauen obs ein Operator ist. if(sWidNet.length() < 1){bParseError=true; return 0.0;} cOP = sWidNet.charAt(0); if(cOP == 'S') { //nach dem Operator darf nichts mehr kommen, da wir //ja die letzte Klammer schon weggeschmissen haben... if(sWidNet.length() > 1){bParseError=true;return 0.0;} //Juhu... wir kennen den Operator und können uns //somit den Wert das Ausdrucks berechnen. for(int j=0; j < vWidValues.size(); j++) result += ((Double)(vWidValues.get(j))).doubleValue(); break; } else if(cOP == 'P') { //siehe oben... *g* if(sWidNet.length() > 1){bParseError=true;return 0.0;} //detto... for(int j=0; j < vWidValues.size(); j++) result += 1.0/((Double)(vWidValues.get(j))).doubleValue(); result = 1 / result; break; } } } else { if(FLAGS.DEBUG) println("in 'parseString()': PARSE ERROR - ABORTING"); bParseError = true; } if(FLAGS.DEBUG) println("in 'parseString()': returnvalue of sequence:\t" + result); //wenn wir hier ankommen, haben wir einen gültigen Ausdruck //gehabt, und kennen jetzt seinen Wert. return result; } /** * <tt>getSubSequence()</tt><br> * holt aus einem verschachtelten Ausdruck den Unterausdruck * heraus.<br> * Eine kleine Graphik:<br> * ((a,b,c,P),x,S) -> (a,b,c,P) * * @return String */ private String getSubSequence(String sSequence) { if(FLAGS.DEBUG) println("in 'getSubSequence()': value at start:\t\t" + sSequence); //in welchem nesting-level bin ich? int iCounter=0; for(int i=0; i < sSequence.length(); i++) { if(sSequence.charAt(i)== SEQUENCEOPEN)iCounter++; if(sSequence.charAt(i)== SEQUENCECLOSE)iCounter--; //aahh, wir haben die passende Endklammer gefunden. if(iCounter == 0) { //somit geb ich den Unterausdruck zurück. String tmp = sSequence.substring(0,++i); if(FLAGS.DEBUG) println("in 'getSubSequence()': value at return:\t\t" + tmp); return tmp; } } //wenn wir hier ankommen, hatte der String einen Syntaxfehler. return " "; } /** * <tt>getSubValue</tt><br> * liefert den Ausdruck vor dem ersten Limiter zurück.<br> * Beispiel:<br> * x,y,P -> x * * @return String */ private String getSubValue(String sValue) { int iPos = sValue.indexOf(LIMITER); //iPos kann -1 werden wenn kein LIMITER gefunden. also machen //wirs auf alle fälle grösser als 0 return sValue.substring(0,(iPos < 0 ? 0 : iPos)); } /** * <tt>getValue</tt><br> * liefert den Wert eines möglichen Symbols zurück.<br> * Beispiel:<br> * 4K7 -> 4700 * * @return double; */ private double getValue(String sValue) { if(FLAGS.DEBUG) println("in 'getValue()': get value of this:\t\t" + sValue); char ctmp= ' '; try{ // wir loopen uns durch den String... for(int i=0; i < sValue.length(); i++) { //...und ersetzen alles was keine Zahl ist duch einen //Dezimalpunkt und multiplizieren mit der entsprechenden //Potenz. ctmp = sValue.charAt(i); if(!Character.isDigit(ctmp)) { switch(ctmp) { case 'M': return Double.parseDouble(sValue.replace('M','.')) * 1000000.0; case 'K': return Double.parseDouble(sValue.replace('K','.')) * 1000.0; case 'R': case '.': return Double.parseDouble(sValue.replace('R','.')); //irgendwas was keine Zahl ist, aber auch kein Symbol... default: return -1.0; } } } return Double.parseDouble(sValue); } //wenn parseDouble eine Exception wirft, können wir davon //ausgehen, dass das Symbol nicht der Spez entspricht. catch(NumberFormatException e){ bParseError = true; return -1.0; } } }