package cz.cuni.mff.java.du2011x1; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; /** DU 1. * * @author Ondrej Moravcik */ public class JLab { // in this variable would be stored the input static BufferedReader input; static int openBraces; static boolean chyba; static boolean printResult; // list of all possible operators static final HashMap operators = new HashMap(6,1); static { chyba = false; printResult = false; openBraces = 0; operators.put("+",0); operators.put("-",0); operators.put("*",1); operators.put("/",1); operators.put(".*",1); operators.put("./",1); } boolean returnFromBraces; public JLab() { this.returnFromBraces = false; } /** * @param args the command line arguments */ public static void main(String[] args) { /* VZOR: kod, ktery opisuje data ze standardniho vstupu na standardni vystup * a konci pokud narazi na konec vstupu. * **/ try { JLab jl = new JLab(); if (args.length == 0) { input = new BufferedReader(new InputStreamReader(System.in)); } else { String fileName = args[0]; File file = new File(fileName); input = new BufferedReader(new InputStreamReader(new FileInputStream(file))); } jl.compute(); //result.print(); } catch(IOException ex) { System.err.println("Nastala IOException"); } } Operand compute() throws IOException { ParsedLine parsedLine = new ParsedLine(); int c; Operator operator = null; Operand operand = null; String number = ""; while ((c = input.read()) != -1) { try { char ch = (char)c; switch(ch) { case '[' : case ']' : case '(' : case ')' : case '+' : case '-' : case '*' : case '/' : case '\n' : if (!number.trim().isEmpty()) { if((number.toLowerCase().endsWith("e") || number.toLowerCase().endsWith("p")) && ch=='-') { number += ch; } else { try { operand = new Scalar(number); } catch(Exception e) { chyba = true; } number=""; } } break; case '.' : // do nothing - will be handled further break; default : number += ch; break; } switch(ch) { // read Matrix case '[' : Matrix matrix = new Matrix(); try { matrix.readMatrix(); } catch (CHYBA ex) { chyba=true; } operand = matrix; break; // evaluate the expression inbetween braces case '(' : ++openBraces; operand = (new JLab()).compute(); break; case ')' : --openBraces; if (openBraces < 0) { //throw new CHYBA("There was closing bracket before opening bracket."); chyba=true; } else { this.returnFromBraces=true; } break; // end of equation case '\n': if (openBraces > 0) { //throw new CHYBA("There was closing bracket before opening bracket."); chyba=true; this.returnFromBraces=true; --openBraces; } printResult = true; break; case '-' : // if the - is at the start of the line it should be added to the number if (parsedLine.isEmpty() && number.isEmpty()) { number += c; } else { if(!(number.toLowerCase().endsWith("e-")||number.toLowerCase().endsWith("p-"))) { // treat as an operator operator = new Operator("-"); } } break; case '+' : operator = new Operator("+"); break; case '*' : operator = new Operator("*"); break; case '/' : operator = new Operator("/"); break; case '.' : c = input.read(); if ((char)c == '*' || (char)c == '/') { operator = new Operator("."+(char)c); } else { number += "." + (char)c; } break; } if(operand != null) { parsedLine.addElement(operand); operand = null; } if (parsedLine.lineElements.size() == 5) { try { parsedLine.lineElements = evaluateStack(parsedLine.lineElements); } catch (Exception e) { chyba = true; } } if(operator != null) { parsedLine.addElement(operator); operator = null; } if(returnFromBraces) { try { return parsedLine.getResult(); } catch(Exception e) { chyba = true; } } if (printResult || c==-1) { if(openBraces != 0) { chyba=true; } openBraces = 0; try { if(!chyba) { parsedLine.getResult().print(); } else { System.out.println("CHYBA"); chyba=false; } } catch (Exception e) { System.out.println("CHYBA"); } parsedLine.lineElements.clear(); printResult = false; System.out.println(); } } catch (IOException ex) { System.err.println("Nastala IOException"); } } return null;//parsedLine.getResult(); } ArrayList evaluateStack(ArrayList lineElements) throws CHYBA { try { ArrayList lE = new ArrayList(5); if (lineElements.size() == 5) { // operands and operators must be interlace if(((Operator)lineElements.get(1)).priority >= ((Operator)lineElements.get(3)).priority) { LineElement operand = evaluate(lineElements.get(0), lineElements.get(1), lineElements.get(2)); lE.add(operand); lE.add(lineElements.get(3)); lE.add(lineElements.get(4)); } else { LineElement operand = evaluate(lineElements.get(2), lineElements.get(3), lineElements.get(4)); lE.add(lineElements.get(0)); lE.add(lineElements.get(1)); lE.add(operand); } } else if(lineElements.size() == 3) { LineElement operand = evaluate(lineElements.get(0), lineElements.get(1), lineElements.get(2)); lE.add(operand); } else { throw new CHYBA("Error during stack evaluation."); } return lE; } catch(Exception e) { throw new CHYBA("Error during stack evaluation."); } } Operand evaluate(LineElement a, LineElement op, LineElement b) throws CHYBA { if ((a instanceof Matrix) && (b instanceof Matrix)) { switch(((Operator)op).notation) { case "*" : return multiply((Matrix)a,(Matrix)b); case "+" : case "-" : case ".*" : case "./" : return elementByElement((Matrix)a,(Matrix)b,(Operator)op); default : throw new CHYBA("This operation is not allowed between matricces."); } } else if((a instanceof Matrix) && (b instanceof Scalar)) { switch(((Operator)op).notation) { case "+" : case "-" : case "*" : case "/" : return elementByElement((Matrix)a,(Scalar)b,(Operator)op); default : throw new CHYBA("This operation is not allowed between matricces."); } } else if((a instanceof Scalar) && (b instanceof Matrix)) { switch(((Operator)op).notation) { case "+" : case "-" : case "*" : //case "/" : could be allowed in case of multiplication by inverse scalar return elementByElement((Scalar)a,(Matrix)b,(Operator)op); default : throw new CHYBA("This operation is not allowed between matricces."); } } else if((a instanceof Scalar) && (b instanceof Scalar)) { switch(((Operator)op).notation) { case "+" : return new Scalar(((Scalar)a).value + ((Scalar)b).value); case "-" : return new Scalar(((Scalar)a).value - ((Scalar)b).value); case "*" : return new Scalar(((Scalar)a).value * ((Scalar)b).value); case "/" : return new Scalar(((Scalar)a).value / ((Scalar)b).value); default : throw new CHYBA("This operation is not allowed between matricces."); } } else throw new CHYBA("This operation is not allowed between matricces."); } Matrix multiply(Matrix a, Matrix b) throws CHYBA { Matrix matrix = new Matrix(); if (a.length != b.height) { throw new CHYBA("Matricces types are incompatible for multiplying."); } else { for(int i = 0; i < a.height;++i) { ArrayList matrixLine = new ArrayList(); for(int j = 0; j < b.length;++j) { Float elem = new Float(0); for(int k = 0; k < a.length;++k) { elem += a.element.get(i).get(k) * b.element.get(k).get(j); } matrixLine.add(elem); } matrix.element.add(matrixLine); } } matrix.setLengtHeight(); return matrix; } Matrix elementByElement(Matrix a, Matrix b,Operator op) throws CHYBA { Matrix matrix = new Matrix(); if (a.length != b.length || a.height != b.height) { throw new CHYBA("Different ranks of matricces."); } else { for(int i = 0; i < a.height;++i) { ArrayList matrixLine = new ArrayList(); for(int j = 0; j < a.length;++j) { switch (op.notation) { case "+" : matrixLine.add(a.element.get(i).get(j) + b.element.get(i).get(j));break; case "-" : matrixLine.add(a.element.get(i).get(j) - b.element.get(i).get(j));break; case ".*" : matrixLine.add(a.element.get(i).get(j) * b.element.get(i).get(j));break; case "./" : matrixLine.add(a.element.get(i).get(j) / b.element.get(i).get(j));break; //default : throw new CHYBA("Unexpected operator."); } } matrix.element.add(matrixLine); } } matrix.setLengtHeight(); return matrix; } Matrix elementByElement(Scalar a, Matrix b,Operator op) throws CHYBA { Matrix matrix = new Matrix(); for(int i = 0; i < b.height;++i) { ArrayList matrixLine = new ArrayList(); for(int j = 0; j < b.length;++j) { switch (op.notation) { case "+" : matrixLine.add(a.value + b.element.get(i).get(j));break; case "-" : matrixLine.add(a.value - b.element.get(i).get(j));break; case "*" : matrixLine.add(a.value * b.element.get(i).get(j));break; //default : throw new CHYBA("Unexpected operator."); } } matrix.element.add(matrixLine); } matrix.setLengtHeight(); return matrix; } Matrix elementByElement(Matrix a, Scalar b,Operator op) throws CHYBA { Matrix matrix = new Matrix(); for(int i = 0; i < a.height;++i) { ArrayList matrixLine = new ArrayList(); for(int j = 0; j < a.length;++j) { switch (op.notation) { case "+" : matrixLine.add(a.element.get(i).get(j) + b.value);break; case "-" : matrixLine.add(a.element.get(i).get(j) - b.value);break; case "*" : matrixLine.add(a.element.get(i).get(j) * b.value);break; case "/" : matrixLine.add(a.element.get(i).get(j) / b.value);break; default : throw new CHYBA("Unexpected operator."); } } matrix.element.add(matrixLine); } matrix.setLengtHeight(); return matrix; } class LineElement{} class Operator extends LineElement { int priority; // this determines the input notation +,-,*,/,.*,./ String notation; public Operator(String notation) { priority = operators.get(notation); this.priority = priority; this.notation = notation; } } enum OPERAND{SCALAR,MATRIX} public static void print(float number) { System.out.printf("%10.5f",number); } class Operand extends LineElement { OPERAND type; void print() { if(this instanceof Matrix) { ((Matrix)this).print(); } else if(this instanceof Scalar) { ((Scalar)this).print(); } } } class Scalar extends Operand { Float value; Scalar(Float value) { this.value = value; } Scalar(String value) { this.value = Float.parseFloat(value); } @Override void print() { print(this.value); System.out.println(); } } class Matrix extends Operand { ArrayList> element; // length of the line int length; int height; Matrix() { this.element = new ArrayList>(); this.length = 0; this.height = 0; } void setLengtHeight() { this.length = this.element.get(0).size(); this.height = this.element.size(); } void readMatrix() throws IOException,CHYBA { char ch; ArrayList matrixLineNumbers; do { matrixLineNumbers = new ArrayList(); ch = readMatrixLine(matrixLineNumbers); this.element.add(matrixLineNumbers); ++(this.height); } while (ch != ']'); } char readMatrixLine(ArrayList matrixLineNumbers) throws IOException,CHYBA { String matrixLine = ""; int c; // boolean doRead = true; // while((c = input.read()) != -1 && doRead) while((c = input.read()) != -1) { char ch = (char)c; // switch(ch) // { // case (';') : ; // case ('\n'): ; // case (']'): doRead=false; // } // reads the line until separator is read if(ch == ';' || ch == '\n' || ch == ']') { break; } matrixLine += (char)c; } if(c == -1) { throw new CHYBA("The matrix wasn't ended properly."); } // Splits the line by spaces " " to array of strings String[] numbers = matrixLine.split(" "); for(String number:numbers) { // empty strings are omitted if(!number.isEmpty()) { matrixLineNumbers.add(Float.parseFloat(number)); } } if(matrixLineNumbers.isEmpty()) { throw new CHYBA("The matrix contained empty line."); } else { if (this.length != 0) { if (this.length != matrixLineNumbers.size()) { // reads until the end of matrix while((c = input.read()) != -1) { char ch = (char)c; if(ch == ']') { break; } } // while((c = input.read()) != -1) // { // char ch = (char)c; // if(ch == '\n') // { // break; // } // } throw new CHYBA("The matrix line lengths don't match."); } } else { // sets the matrix line length if the line wasn't previously set this.length = matrixLineNumbers.size(); } } return (char)c; } @Override public void print() { for (int i = 0; i < this.height; ++i) { for( int j = 0; j < this.length; ++j) { print(this.element.get(i).get(j)); } System.out.println(); } } } class ParsedLine { ArrayList lineElements; ParsedLine() { this.lineElements = new ArrayList(5); } Operand getResult() throws CHYBA { try { // the stack could not be filled more while(this.lineElements.size() > 1) { this.lineElements = evaluateStack(this.lineElements); } Operand result = (Operand)this.lineElements.get(0); return result; } catch(Exception e) { // an class cast exception could originate throw new CHYBA(e.getMessage()); } } void addElement(LineElement le) { this.lineElements.add(le); } boolean isEmpty() { return this.lineElements.isEmpty(); } } class CHYBA extends Exception { public CHYBA(String message) { super(message); } private CHYBA() { super(); } } }