// author: klaffenboeck patrick <patrick.k@rocketmail.com> // matr.-nr: 0125335 // bsp.-nr: 1132 // beschreibung: lieszt einen String ein, der einen mathematischen // - " - : ausdruck mit vektoren enthaelt und gibt das ergebnis // - " - : aus. moechte noch kurz sagen, dass ich mit dem // - " - : programm eigenltich NICHT zufrieden bin. der grund // - " - : steht in Vektoren.txt. // danke an gck, fuer den hinweis auf die klasse Vector! // for better readability try "sed '/^ \/\//d' ...." ;-) import eprog.EprogIO; import java.util.Vector; import VectorObject; import Calculator; public class Vektoren { // in Vektoren.txt wird erklaert warum ich einen // Vector zum organisieren meiner daten nehme. public static Vector termv = null; public static void main( String args[] ) { String terms; VectorObject result; float x, y, z; int i; terms = EprogIO.readWord(); // die hier aufgerufenen methoden werden in Vektoren.txt // erklaert. try { quickSyntaxCheck(terms); termsToTermv(terms); convertVectors(); processPrefixes(); convertScalars(); solveBrackets(); calculate(0, termv.size() - 1); } catch (Exception e) { EprogIO.println("FALSCHE EINGABE"); System.exit(0); } // nachdem alle operationen durchgefuehrt wurden, // ist nur noch das ergebenis im Vector result = getVO(0); // und laut spezifikation muss das ein vektor sein if (result.getType() != VectorObject.VECTOR) { EprogIO.println("FALSCHE EINGABE"); System.exit(0); } // dessen werte nun ausgelesen und ausgegeben werden koennen x = (float) result.getX(); y = (float) result.getY(); z = (float) result.getZ(); EprogIO.print("[ "); EprogIO.printFixed(x); EprogIO.print(" , "); EprogIO.printFixed(y); EprogIO.print(" , "); EprogIO.printFixed(z); EprogIO.println(" ]"); } // end void main( String[] ) /* * ueberprueft wird: * - ob jede oeffnende klammer auch eine schlieszende hat * - ob fuer jede geschlossene klammer vorher ueberhaupt * eine geoeffnet wurde * - ob mehr als eine eckige klammer offen ist * - ob mehr als zwei runde klammern offen sind * (einschraenkung von EProg) * - ob ueberhaupt ein vektor vorkommt * * bei einem fehler wird eine Exception geworfen. */ public static void quickSyntaxCheck( String terms ) throws Exception { int i; int brackets = 0; int sqBrackets = 0; int currentChar = 255; boolean containsVector = false; for (i = 0; i < terms.length(); i++) { currentChar = terms.charAt(i); switch (currentChar) { case '(': brackets++; if (brackets > 2) throw new Exception(); break; case ')': brackets--; if (brackets < 0) throw new Exception(); break; case '[': sqBrackets++; if (sqBrackets > 1) throw new Exception(); break; case ']': sqBrackets--; if (sqBrackets < 0) throw new Exception(); // wir haben mindestens ein oeffnene und eine schlieszende eckige klammer, also ... containsVector = true; break; } } if ((brackets != 0) | (sqBrackets != 0)) throw new Exception(); if (containsVector == false) throw new Exception(); } // end void quickSyntaxCheck( String ) /* * lieszt jedes zeichen des Strings ein, wandelt ihn ihn ein object * und haengt es an den Vector. */ public static void termsToTermv( String terms ) throws Exception { int i; termv = new Vector(terms.length()); for (i = 0; i < terms.length(); i++) termv.add(new VectorObject(terms.charAt(i))); } // end Vector termsToTermv( String ) /* * wird eine oeffnende eckige klammer gefunden, wird an dieser * stelle (pos) angefangen einen vektor einzulesen. */ public static void convertVectors() throws Exception { int pos; int curr = 0; for (pos = 0; pos < termv.size(); pos++) { curr = (getVO(pos)).getType(); if (curr == VectorObject.L_SQ_BRACKET) scanVector(pos); } } // end void convertVectors() /* * zwei operatoren hintereinander koennen bedeuten, * dass einer nur ein vorzeichen ist. hier wird das * vorzeichen auf den nachetehenden operanden angewand. */ public static void processPrefixes() throws Exception { int pos; boolean lastWasOperator = false; VectorObject curr, next, tmp; for (pos = 0; pos < termv.size() - 1; pos++) { curr = getVO(pos); next = getVO(pos + 1); if (curr.isPrefix()) { if (lastWasOperator) { tmp = (new Calculator(curr, next)).prefix(); termv.set(pos, tmp); termv.remove(pos + 1); lastWasOperator = false; } else lastWasOperator = true; } else lastWasOperator = curr.isOperator(); } } /* * wenn eine oeffnende klammer gefunden wird, darf dahinter nur * folgendes stehen: noch eine oeffnende klammer, ein vektor * ein vorzeichen, oder eine ziffer. bei den letzten beiden, wird * ab dieser stelle ein skalar eingelesen. kommt ganz was anderes * war die eingabe falsch. */ public static void convertScalars() throws Exception { int pos; VectorObject curr, next, tmp; next = getVO(0); // ganz am anfang des ausdrucks darf nur ein vektor oder eine oeffnende // klammer sein. if ((next.getType() != VectorObject.VECTOR) & (next.getType() != VectorObject.L_BRACKET)) throw new Exception(); for (pos = 0; pos < termv.size() - 1; pos++) { curr = next; next = getVO(pos + 1); if (curr.isLBr()) { if (next.isPrefix() | next.isDigit()) { tmp = new VectorObject(scanScalar(pos + 1)); termv.set(pos, tmp); // da skalare in klammern stehen, muss danach eine schlieszende kommen tmp = getVO(pos + 1); if (!tmp.isRBr()) throw new Exception(); termv.remove(pos + 1); } else if (!next.isVector() & !next.isLBr()) throw new Exception(); } } } // end void convertScalars() /* * loest alle klammernausdruecke und ersetzt sie durch * einen einzigen wert im Vector. */ public static void solveBrackets() throws Exception { int openBr, closeBr; // die positionen der klammern suchen openBr = search(VectorObject.L_BRACKET); closeBr = search(VectorObject.R_BRACKET); // solange welche gefunden werden, auswerten while (openBr != -1) { // das innere der klammer aufloesen calculate(openBr + 1, closeBr - 1); // danach steht nur noch ein operand zwischen den klammern // dadurch hat sich die schlieszende klammer nach vor verschoben // die klammer neu suchen und beide loeschen closeBr = search(VectorObject.R_BRACKET); termv.remove(closeBr); termv.remove(openBr); // das naechste klammernpaar suchen und die schleife von vorne beginnen openBr = search(VectorObject.L_BRACKET); closeBr = search(VectorObject.R_BRACKET); } } /* * start und end sind da, damit man die methode auf das innere * einer klammer beschraenken kann. */ public static void calculate(int start, int end ) throws Exception { int pos; // solange multiplikationen gefunden werden sagen wir giveToCalculator // wo die operation gefunden wurde. dann werden von ende zwei // abgezogen, weil der operator und der zweite operand aus dem Vector // geloescht wurden. while ((pos = search(VectorObject.MULT, start, end)) != -1) { giveToCalculator(pos); end -= 2; } while ((pos = search(VectorObject.PLUS, start, end)) != -1) { giveToCalculator(pos); end -= 2; } while ((pos = search(VectorObject.MINUS, start, end)) != -1) { giveToCalculator(pos); end -= 2; } if (start != end) throw new Exception(); } // end void calculate( int, int ) public static void giveToCalculator( int pos ) throws Exception { VectorObject operand1, operator, operand2, result; // der erste operand operand1 = getVO(pos - 1); // der operator operator = getVO(pos); // der zeite operand operand2 = getVO(pos + 1); // das ergebnis ueberschreibt den ersten operanden // der operator und der zweite operand werden geloescht result = (new Calculator(operand1, operator, operand2)).run(); termv.set(pos - 1, result); termv.remove(pos + 1); termv.remove(pos); } // end void giveToCalculator( int ) /* * lieszt die als einzelne chars gespeicherten daten eines * vektors aus dem Vector und speichert ihn in ein einziges * objekt. */ public static void scanVector( final int pos ) throws Exception { VectorObject tmp; String x, y, z; // ganz am anfang ist eine eckige klammer, die koennen // wir loeschen. termv.remove(pos); // danach kommt ein skalar x = scanScalar(pos); // dann _muss_ ein beistrich kommen, dass wir dann // auch loeschen. tmp = getVO(pos); if (tmp.getC() != ',') throw new Exception(); termv.remove(pos); // wieder ein skalar, ..., ..., ... y = scanScalar(pos); tmp = getVO(pos); if (tmp.getC() != ',') throw new Exception(); termv.remove(pos); z = scanScalar(pos); // am schluss muss eine schlieszende eckige klammer kommen tmp = getVO(pos); if (tmp.getC() != ']') throw new Exception(); // die wird mit dem gesamten vektor ueberschrieben termv.set(pos, new VectorObject(x, y, z)); } // end void scanVector( int ) /* * damit man diese methode auch in den anderen verwenden kann * schreibt sie kein objekt inden Vector, sondern liefert einen * String zurueck. preDot und postDot werden in Vektoren.txt erklaert. */ public static String scanScalar( final int pos ) throws Exception { VectorObject tmp; StringBuffer value = new StringBuffer(10); double x; boolean preDot = false; boolean postDot = true; tmp = getVO(pos); // als erstes _kann_ ein vorzeichen kommen. // wenn ja, an den String anhaengen und aus dem Vector loeschen. if (tmp.isPrefix()) { value.append(tmp.getC()); termv.remove(pos); tmp = getVO(pos); } // dann koennen beliebig viele ziffern kommen ... while (tmp.isDigit()) { value.append(tmp.getC()); termv.remove(pos); tmp = getVO(pos); preDot = true; } // dann _kann_ ein dezimalpunkt da sein ... if (tmp.isDot()) { value.append(tmp.getC()); termv.remove(pos); tmp = getVO(pos); postDot = false; } // dann muessen natuerlich auch wieder ziffern da sein while (tmp.isDigit()) { value.append(tmp.getC()); termv.remove(pos); tmp = getVO(pos); postDot = true; } // wenn vor, oder nach einem punkt keine ziffern sind, wird abgebrochen. if (!(preDot & postDot)) throw new Exception(); // der einfachheit halber, wandle ich das ergebnis kurz in einen // double um um zu ueberpruefen, ob es im richtigen bereich liegt // (EProg einschraenkung) x = Double.parseDouble(value.toString()); if ((x < -100) | (x > 100)) throw new Exception(); return value.toString(); } // end String scanVector( final int ) /* * durchsucht den gesamten Vector und liefert die erste * position an der ein eintrag vom typ <type> ist, zurueck. */ public static int search( int type ) { int i; for (i = 0; i < termv.size(); i++) if ((getVO(i)).getType() == type) return i; return -1; } // end int search( int ) /* * wie search( int ), aber sucht nur in einem gewissen bereich. */ public static int search( int type, int start, int end ) { int i; for (i = start + 1; i <= end; i++) if ((getVO(i)).getType() == type) return i; return -1; } // end int search( int, int ) /* * liefert das objekt, das an der position <pos> im * Vector ist. */ public static VectorObject getVO( int pos ) { return (VectorObject) termv.get(pos); } // end VectorObject getVO ( int ) } // end class Vektoren