From 57fc8cfa44a8252b6044e22256bad9eebcba5a41 Mon Sep 17 00:00:00 2001 From: XDrake99 Date: Tue, 11 Apr 2017 22:04:44 +0200 Subject: [PATCH] Added new expression blocks, like parentheses and power of x --- res/draft unknown variable choice.png | Bin 0 -> 6019 bytes res/font_ex.rft | Bin 1667 -> 1735 bytes .../gui/expression/BlockContainer.java | 28 +- .../expression/BlockExponentialNotation.java | 8 + .../gui/expression/BlockParenthesis.java | 16 +- .../gui/expression/BlockPower.java | 97 ++++++ .../expression/containers/InputContainer.java | 4 + .../containers/NormalInputContainer.java | 15 +- .../picalculator/math/parser/MathParser.java | 303 ++++++++++++++---- .../parser/features/FeatureParenthesis.java | 9 + .../math/parser/features/FeaturePower.java | 11 + .../parser/features/FeatureSquareRoot.java | 9 + 12 files changed, 424 insertions(+), 76 deletions(-) create mode 100644 res/draft unknown variable choice.png create mode 100644 src/org/warp/picalculator/gui/expression/BlockExponentialNotation.java create mode 100644 src/org/warp/picalculator/gui/expression/BlockPower.java create mode 100644 src/org/warp/picalculator/math/parser/features/FeatureParenthesis.java create mode 100644 src/org/warp/picalculator/math/parser/features/FeaturePower.java create mode 100644 src/org/warp/picalculator/math/parser/features/FeatureSquareRoot.java diff --git a/res/draft unknown variable choice.png b/res/draft unknown variable choice.png new file mode 100644 index 0000000000000000000000000000000000000000..973440c9c479ed6694ec4cd3e9b543b7a5af45ef GIT binary patch literal 6019 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 literal 0 HcmV?d00001 diff --git a/res/font_ex.rft b/res/font_ex.rft index 18475d17b8a623898f8be31c5a89b29160dce17a..26f2257b236effc0bbdf561908fb75a29002ec0a 100644 GIT binary patch delta 76 zcmZqXJYOU@G#V42A>= H9*}MT{&@?N delta 7 OcmX@k+swP6nGFC7r2?J+ diff --git a/src/org/warp/picalculator/gui/expression/BlockContainer.java b/src/org/warp/picalculator/gui/expression/BlockContainer.java index bd553ab7..8f2af1b1 100644 --- a/src/org/warp/picalculator/gui/expression/BlockContainer.java +++ b/src/org/warp/picalculator/gui/expression/BlockContainer.java @@ -11,29 +11,34 @@ public class BlockContainer implements GraphicalElement { private static boolean initialized = false; - private final int minWidth; - private final int minHeight; + private int minWidth; + private int minHeight; private final ObjectArrayList content; private boolean small; private int width; private int height; private int line; public final boolean withBorder; + private boolean autoMinimums; public BlockContainer() { this(false, BlockContainer.getDefaultCharWidth(false), BlockContainer.getDefaultCharHeight(false), true); + autoMinimums = true; } public BlockContainer(boolean small) { this(small, BlockContainer.getDefaultCharWidth(small), BlockContainer.getDefaultCharHeight(small), true); + autoMinimums = true; } public BlockContainer(boolean small, boolean withBorder) { this(small, BlockContainer.getDefaultCharWidth(small), BlockContainer.getDefaultCharHeight(small), withBorder); + autoMinimums = true; } public BlockContainer(boolean small, int minWidth, int minHeight, boolean withBorder) { this(small, minWidth, minHeight, new ObjectArrayList<>(), withBorder); + autoMinimums = false; } public BlockContainer(boolean small, int minWidth, int minHeight, ObjectArrayList content, boolean withBorder) { @@ -111,9 +116,9 @@ public class BlockContainer implements GraphicalElement { if (caret.getRemaining() == 0) { if (content.size() > 0) { - BlockContainer.drawCaret(ge, r, caret, x, y + line - content.get(0).line, content.get(0).height); + BlockContainer.drawCaret(ge, r, caret, small, x, y + line - content.get(0).line, content.get(0).height); } else { - BlockContainer.drawCaret(ge, r, caret, x, y, height); + BlockContainer.drawCaret(ge, r, caret, small, x, y, height); } } @@ -128,7 +133,7 @@ public class BlockContainer implements GraphicalElement { b.draw(ge, r, x + paddingX, y + line - b.line, caret); paddingX += b.getWidth(); if (caret.getRemaining() == 0) { - BlockContainer.drawCaret(ge, r, caret, x + paddingX, y + line - b.line, b.height); + BlockContainer.drawCaret(ge, r, caret, small, x + paddingX, y + line - b.line, b.height); } paddingX += 1; } @@ -271,17 +276,22 @@ public class BlockContainer implements GraphicalElement { return defFontSizes[b ? 3 : 1]; } - public static void drawCaret(GraphicEngine ge, Renderer r, Caret caret, int x, int y, int height) { + public static void drawCaret(GraphicEngine ge, Renderer r, Caret caret, boolean small, int x, int y, int height) { if (caret.getState() == CaretState.VISIBLE_ON) { r.glColor(getDefaultColor()); - r.glDrawLine(x, y, x, y - 1 + height); - r.glDrawLine(x + 1, y, x + 1, y - 1 + height); - r.glDrawLine(x + 2, y, x + 2, y - 1 + height); + r.glFillColor(x, y, small?2:3, height); } } public void setSmall(boolean small) { this.small = small; + if (this.autoMinimums) { + this.minWidth = BlockContainer.getDefaultCharWidth(small); + this.minHeight = BlockContainer.getDefaultCharHeight(small); + } + for (Block b : this.content) { + b.setSmall(small); + } recomputeDimensions(); } diff --git a/src/org/warp/picalculator/gui/expression/BlockExponentialNotation.java b/src/org/warp/picalculator/gui/expression/BlockExponentialNotation.java new file mode 100644 index 00000000..14511a5e --- /dev/null +++ b/src/org/warp/picalculator/gui/expression/BlockExponentialNotation.java @@ -0,0 +1,8 @@ +package org.warp.picalculator.gui.expression; + +public class BlockExponentialNotation extends BlockPower { + @Override + protected int getSpacing() { + return -3; + } +} diff --git a/src/org/warp/picalculator/gui/expression/BlockParenthesis.java b/src/org/warp/picalculator/gui/expression/BlockParenthesis.java index 91c89e27..104c8ee1 100644 --- a/src/org/warp/picalculator/gui/expression/BlockParenthesis.java +++ b/src/org/warp/picalculator/gui/expression/BlockParenthesis.java @@ -1,5 +1,6 @@ package org.warp.picalculator.gui.expression; +import org.warp.picalculator.gui.graphicengine.BinaryFont; import org.warp.picalculator.gui.graphicengine.GraphicEngine; import org.warp.picalculator.gui.graphicengine.Renderer; @@ -9,6 +10,9 @@ public class BlockParenthesis extends Block { private final BlockContainer containerNumber; + private int chw; + private int chh; + public BlockParenthesis() { containerNumber = new BlockContainer(false); recomputeDimensions(); @@ -18,7 +22,13 @@ public class BlockParenthesis extends Block { public void draw(GraphicEngine ge, Renderer r, int x, int y, Caret caret) { BlockContainer.getDefaultFont(small).use(ge); r.glColor(BlockContainer.getDefaultColor()); - containerNumber.draw(ge, r, x + 7, y + 3, caret); + r.glDrawCharLeft(x, y, '╭'); + r.glDrawCharLeft(x, y+height-chh, '╰'); + r.glFillColor(x+3, y+6, 2, height-6*2); + r.glFillColor(x+width-5, y+6, 2, height-6*2); + r.glDrawCharLeft(x+width-chw, y, '╮'); + r.glDrawCharLeft(x+width-chw, y+height-chh, '╯'); + containerNumber.draw(ge, r, x+chw, y, caret); } @Override @@ -43,7 +53,9 @@ public class BlockParenthesis extends Block { @Override public void recomputeDimensions() { - width = containerNumber.getWidth() + BlockContainer.getDefaultCharWidth(small) * 2; + chw = BlockContainer.getDefaultCharWidth(small); + chh = BlockContainer.getDefaultCharHeight(small); + width = containerNumber.getWidth() + chw * 2 + 3; height = containerNumber.getHeight(); line = containerNumber.getLine(); } diff --git a/src/org/warp/picalculator/gui/expression/BlockPower.java b/src/org/warp/picalculator/gui/expression/BlockPower.java new file mode 100644 index 00000000..df8f5984 --- /dev/null +++ b/src/org/warp/picalculator/gui/expression/BlockPower.java @@ -0,0 +1,97 @@ +package org.warp.picalculator.gui.expression; + +import org.warp.picalculator.gui.expression.Block; +import org.warp.picalculator.gui.expression.BlockContainer; +import org.warp.picalculator.gui.expression.Caret; +import org.warp.picalculator.gui.graphicengine.GraphicEngine; +import org.warp.picalculator.gui.graphicengine.Renderer; + +public class BlockPower extends Block { + + public static final int CLASS_ID = 0x00000005; + + private final BlockContainer containerNumber; + private final BlockContainer containerExponent; + + private int h1; + private int w1; + + public BlockPower() { + containerNumber = new BlockContainer(false); + containerExponent = new BlockContainer(true); + recomputeDimensions(); + } + + @Override + public void draw(GraphicEngine ge, Renderer r, int x, int y, Caret caret) { + BlockContainer.getDefaultFont(small).use(ge); + r.glColor(BlockContainer.getDefaultColor()); + containerNumber.draw(ge, r, x, y+height-h1, caret); + BlockContainer.getDefaultFont(true).use(ge); + containerExponent.draw(ge, r, x+w1+getSpacing(), y, caret); + } + + @Override + public boolean putBlock(Caret caret, Block newBlock) { + boolean added = false; + added = added | containerNumber.putBlock(caret, newBlock); + added = added | containerExponent.putBlock(caret, newBlock); + if (added) { + recomputeDimensions(); + } + return added; + } + + @Override + public boolean delBlock(Caret caret) { + boolean removed = false; + removed = removed | containerNumber.delBlock(caret); + removed = removed | containerExponent.delBlock(caret); + if (removed) { + recomputeDimensions(); + } + return removed; + } + + @Override + public void recomputeDimensions() { + w1 = containerNumber.getWidth(); + final int w2 = containerExponent.getWidth(); + h1 = containerNumber.getHeight(); + final int h2 = containerExponent.getHeight(); + final int l1 = containerNumber.getLine(); + width = w1+getSpacing()+1+w2; + height = h1 + h2 - 3; + line = height-h1+l1; + } + + @Override + public void setSmall(boolean small) { + this.small = small; + containerNumber.setSmall(small); + containerExponent.setSmall(true); + recomputeDimensions(); + } + + public BlockContainer getNumberContainer() { + return containerNumber; + } + + public BlockContainer getExponentContainer() { + return containerExponent; + } + + @Override + public int getClassID() { + return CLASS_ID; + } + + @Override + public int computeCaretMaxBound() { + return containerNumber.computeCaretMaxBound() + containerExponent.computeCaretMaxBound(); + } + + protected int getSpacing() { + return 1; + } +} diff --git a/src/org/warp/picalculator/gui/expression/containers/InputContainer.java b/src/org/warp/picalculator/gui/expression/containers/InputContainer.java index 6f734fb6..6e857f95 100644 --- a/src/org/warp/picalculator/gui/expression/containers/InputContainer.java +++ b/src/org/warp/picalculator/gui/expression/containers/InputContainer.java @@ -74,6 +74,8 @@ public abstract class InputContainer implements GraphicalElement, InputLayout, S final int curPos = caret.getPosition(); if (curPos > 0) { caret.setPosition(curPos - 1); + } else { + caret.setPosition(maxPosition-1); } caret.turnOn(); caretTime = 0; @@ -83,6 +85,8 @@ public abstract class InputContainer implements GraphicalElement, InputLayout, S final int curPos = caret.getPosition(); if (curPos + 1 < maxPosition) { caret.setPosition(curPos + 1); + } else { + caret.setPosition(0); } caret.turnOn(); caretTime = 0; diff --git a/src/org/warp/picalculator/gui/expression/containers/NormalInputContainer.java b/src/org/warp/picalculator/gui/expression/containers/NormalInputContainer.java index ec6aadd8..9efe4cfb 100644 --- a/src/org/warp/picalculator/gui/expression/containers/NormalInputContainer.java +++ b/src/org/warp/picalculator/gui/expression/containers/NormalInputContainer.java @@ -4,6 +4,7 @@ import org.warp.picalculator.gui.expression.Block; import org.warp.picalculator.gui.expression.BlockChar; import org.warp.picalculator.gui.expression.BlockDivision; import org.warp.picalculator.gui.expression.BlockParenthesis; +import org.warp.picalculator.gui.expression.BlockPower; import org.warp.picalculator.gui.expression.BlockSquareRoot; import org.warp.picalculator.math.MathematicalSymbols; @@ -29,8 +30,12 @@ public class NormalInputContainer extends InputContainer { case MathematicalSymbols.SQUARE_ROOT: return new BlockSquareRoot(); case MathematicalSymbols.PARENTHESIS_OPEN: - case MathematicalSymbols.PARENTHESIS_CLOSE: return new BlockParenthesis(); + case MathematicalSymbols.PARENTHESIS_CLOSE: + return null; + case MathematicalSymbols.POWER: + case MathematicalSymbols.POWER_OF_TWO: + return new BlockPower(); case MathematicalSymbols.MULTIPLICATION: case MathematicalSymbols.SUM: case MathematicalSymbols.SUM_SUBTRACTION: @@ -50,4 +55,12 @@ public class NormalInputContainer extends InputContainer { return new BlockChar(c); } } + + @Override + public void typeChar(char c) { + super.typeChar(c); + if (c == MathematicalSymbols.PARENTHESIS_CLOSE) { + this.moveRight(); + } + } } diff --git a/src/org/warp/picalculator/math/parser/MathParser.java b/src/org/warp/picalculator/math/parser/MathParser.java index 8bd44f50..4a4c7552 100644 --- a/src/org/warp/picalculator/math/parser/MathParser.java +++ b/src/org/warp/picalculator/math/parser/MathParser.java @@ -10,6 +10,10 @@ import org.warp.picalculator.gui.expression.Block; import org.warp.picalculator.gui.expression.BlockChar; import org.warp.picalculator.gui.expression.BlockContainer; import org.warp.picalculator.gui.expression.BlockDivision; +import org.warp.picalculator.gui.expression.BlockExponentialNotation; +import org.warp.picalculator.gui.expression.BlockParenthesis; +import org.warp.picalculator.gui.expression.BlockPower; +import org.warp.picalculator.gui.expression.BlockSquareRoot; import org.warp.picalculator.gui.expression.containers.InputContainer; import org.warp.picalculator.math.Function; import org.warp.picalculator.math.FunctionOperator; @@ -17,6 +21,8 @@ import org.warp.picalculator.math.FunctionSingle; import org.warp.picalculator.math.MathContext; import org.warp.picalculator.math.MathematicalSymbols; import org.warp.picalculator.math.functions.Number; +import org.warp.picalculator.math.functions.Power; +import org.warp.picalculator.math.functions.RootSquare; import org.warp.picalculator.math.functions.Subtraction; import org.warp.picalculator.math.functions.Sum; import org.warp.picalculator.math.functions.SumSubtraction; @@ -29,12 +35,17 @@ import org.warp.picalculator.math.parser.features.FeatureChar; import org.warp.picalculator.math.parser.features.FeatureDivision; import org.warp.picalculator.math.parser.features.FeatureMultiplication; import org.warp.picalculator.math.parser.features.FeatureNumber; +import org.warp.picalculator.math.parser.features.FeatureParenthesis; +import org.warp.picalculator.math.parser.features.FeaturePower; +import org.warp.picalculator.math.parser.features.FeatureSquareRoot; import org.warp.picalculator.math.parser.features.FeatureSum; import org.warp.picalculator.math.parser.features.FeatureVariable; import org.warp.picalculator.math.parser.features.interfaces.Feature; import org.warp.picalculator.math.parser.features.interfaces.FeatureDouble; +import org.warp.picalculator.math.parser.features.interfaces.FeatureSingle; import com.sun.org.apache.xpath.internal.functions.Function2Args; +import com.sun.org.apache.xpath.internal.operations.Mult; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectListIterator; @@ -50,7 +61,7 @@ public class MathParser { return result; } - public static ObjectArrayList parseOutput(MathContext context, ObjectArrayList expr) { + public static ObjectArrayList parseOutput(MathContext context, ObjectArrayList expr) throws Error { final ObjectArrayList resultBlocks = new ObjectArrayList<>(); for (Function f : expr) { @@ -60,7 +71,7 @@ public class MathParser { return resultBlocks; } - private static ObjectArrayList parseFunction(MathContext context, Function func) { + private static ObjectArrayList parseFunction(MathContext context, Function func) throws Error { ObjectArrayList result = new ObjectArrayList<>(); if (func instanceof FunctionOperator) { ObjectArrayList sub1 = parseFunction(context, func.getParameter(0)); @@ -71,23 +82,124 @@ public class MathParser { result.addAll(sub2); return result; } + if (func instanceof Subtraction) { + result.addAll(sub1); + result.add(new BlockChar(MathematicalSymbols.SUBTRACTION)); + result.addAll(sub2); + return result; + } + if (func instanceof SumSubtraction) { + result.addAll(sub1); + result.add(new BlockChar(MathematicalSymbols.SUM_SUBTRACTION)); + result.addAll(sub2); + return result; + } + if (func instanceof Multiplication) { + Block nearLeft = sub1.get(sub1.size()-1); + Block nearRight = sub2.get(0); + + result.addAll(sub1); + if (nearLeft instanceof BlockChar && nearRight instanceof BlockChar) { + + } else { + result.add(new BlockChar(MathematicalSymbols.MULTIPLICATION)); + } + result.addAll(sub2); + return result; + } + if (func instanceof Division) { + BlockDivision bd = new BlockDivision(); + BlockContainer uc = bd.getUpperContainer(); + BlockContainer lc = bd.getLowerContainer(); + for (Block b : sub1) { + uc.appendBlockUnsafe(b); + } + for (Block b : sub2) { + lc.appendBlockUnsafe(b); + } + uc.recomputeDimensions(); + lc.recomputeDimensions(); + bd.recomputeDimensions(); + result.add(bd); + return result; + } + if (func instanceof Power) { + BlockPower bp = new BlockPower(); + BlockContainer nc = bp.getNumberContainer(); + BlockContainer ec = bp.getExponentContainer(); + for (Block b : sub1) { + nc.appendBlockUnsafe(b); + } + for (Block b : sub2) { + ec.appendBlockUnsafe(b); + } + nc.recomputeDimensions(); + ec.recomputeDimensions(); + bp.recomputeDimensions(); + result.add(bp); + return result; + } + } + if (func instanceof FunctionSingle) { + ObjectArrayList sub = parseFunction(context, func.getParameter(0)); + if (func instanceof RootSquare) { + BlockSquareRoot bsqr = new BlockSquareRoot(); + BlockContainer bsqrc = bsqr.getNumberContainer(); + for (Block b : sub) { + bsqrc.appendBlockUnsafe(b); + } + bsqrc.recomputeDimensions(); + bsqr.recomputeDimensions(); + result.add((bsqr)); + return result; + } + + } + if (func instanceof Expression) { + ObjectArrayList sub = parseFunction(context, ((Expression) func).getParameter(0)); + BlockParenthesis bp = new BlockParenthesis(); + BlockContainer bpc = bp.getNumberContainer(); + for (Block b : sub) { + bpc.appendBlockUnsafe(b); + } + bpc.recomputeDimensions(); + bp.recomputeDimensions(); + result.add(bp); + return result; } if (func instanceof Number) { Number numb = (Number) func; - BigDecimal decimal = numb.getTerm(); - String numberString; - if (numb.isInteger()) { - BigInteger integ = decimal.toBigInteger(); - numberString = integ.toString(); + String numberString = numb.toString(); + if (numberString.contains("ℯ℮")) { + String[] numberParts = numberString.split("ℯ℮", 2); + numberParts[0]+="ℯ℮"; + BlockPower bp = new BlockExponentialNotation(); + BlockContainer bpnc = bp.getNumberContainer(); + BlockContainer bpec = bp.getExponentContainer(); + for (char c : numberParts[0].toCharArray()) { + bpnc.appendBlockUnsafe(new BlockChar(c)); + } + for (char c : numberParts[1].toCharArray()) { + bpec.appendBlockUnsafe(new BlockChar(c)); + } + bpnc.recomputeDimensions(); + bpec.recomputeDimensions(); + bp.recomputeDimensions(); + result.add(bp); + return result; } else { - numberString = decimal.toPlainString(); - } - for (char c : numberString.toCharArray()) { - result.add(new BlockChar(c)); + for (char c : numberString.toCharArray()) { + result.add(new BlockChar(c)); + } } return result; } - throw new UnsupportedOperationException("Unknown function " + func.getClass().getSimpleName()); + if (func instanceof Variable) { + //TODO: Temporary solution. In near future Variables will be distint objects and they will have a color. So they will be no longer a BlockChar/FeatureChar + result.add(new BlockChar(((Variable) func).getChar())); + return result; + } + throw new Error(Errors.NOT_IMPLEMENTED, "Unknown function " + func.getClass().getSimpleName()); } private static Function parseContainer(final MathContext context, final Iterable blocks) throws Error { @@ -117,8 +229,24 @@ public class MathParser { final Function lower = parseContainer(context, bd.getLowerContainer().getContent()); result = new FeatureDivision(upper, lower); break; + case BlockSquareRoot.CLASS_ID: + final BlockSquareRoot bsqr = (BlockSquareRoot) block; + final Function contnt = parseContainer(context, bsqr.getNumberContainer().getContent()); + result = new FeatureSquareRoot(contnt); + break; + case BlockParenthesis.CLASS_ID: + final BlockParenthesis bp = (BlockParenthesis) block; + final Function cont = parseContainer(context, bp.getNumberContainer().getContent()); + result = new FeatureParenthesis(cont); + break; + case BlockPower.CLASS_ID: + final BlockPower blp = (BlockPower) block; + final Function nmb = parseContainer(context, blp.getNumberContainer().getContent()); + final Function exp = parseContainer(context, blp.getExponentContainer().getContent()); + result = new FeaturePower(nmb, exp); + break; default: - throw new Error(Errors.SYNTAX_ERROR); + throw new Error(Errors.NOT_IMPLEMENTED, "The block " + block.getClass().getSimpleName() + " isn't a known BLock"); } return result; @@ -141,76 +269,117 @@ public class MathParser { private static void fixStack(MathContext context, ObjectArrayList process) throws Error { - //Phase 1 - ObjectListIterator stackIterator = process.listIterator(process.size()); - Function lastElement = null; - while (stackIterator.hasPrevious()) { - final Function f = stackIterator.previous(); - - if (f instanceof FunctionSingle) { - if (((FunctionSingle) f).getParameter() == null) { - if (lastElement == null) { - throw new Error(Errors.MISSING_ARGUMENTS, "There is a function at the end without any argument specified."); - } else { - ((FunctionSingle) f).setParameter(lastElement); - process.remove(stackIterator.nextIndex()); + boolean lastLoopDidSomething; + + ObjectListIterator stackIterator; + + //Phase 0: join number and variables ([2][x] => [[2]*[x]]) + do { + lastLoopDidSomething = false; + stackIterator = process.listIterator(process.size()); + Function lastElement = null; + while (stackIterator.hasPrevious()) { + final Function f = stackIterator.previous(); + final int curIndex = stackIterator.nextIndex(); + + if (f instanceof Number | f instanceof Variable) { + if (lastElement instanceof Variable) { + lastLoopDidSomething = true; + final Function var = process.get(curIndex + 1); + final Function numb = process.get(curIndex); + stackIterator.set(new Multiplication(context, numb, var)); + process.remove(curIndex + 1); } } + lastElement = f; } - lastElement = f; - } + } while (lastLoopDidSomething); + + //Phase 1 + do { + lastLoopDidSomething = false; + stackIterator = process.listIterator(process.size()); + Function lastElement = null; + while (stackIterator.hasPrevious()) { + final Function f = stackIterator.previous(); + + if (f instanceof FunctionSingle) { + if (((FunctionSingle) f).getParameter() == null) { + lastLoopDidSomething = true; + if (lastElement == null) { + throw new Error(Errors.MISSING_ARGUMENTS, "There is a function at the end without any argument specified."); + } else { + ((FunctionSingle) f).setParameter(lastElement); + process.remove(stackIterator.nextIndex()); + } + } + } + lastElement = f; + } + } while (lastLoopDidSomething); //Phase 2 - stackIterator = process.listIterator(); - while (stackIterator.hasNext()) { - final Function f = stackIterator.next(); - final int curIndex = stackIterator.previousIndex(); + do { + lastLoopDidSomething = false; + stackIterator = process.listIterator(); + while (stackIterator.hasNext()) { + final Function f = stackIterator.next(); + final int curIndex = stackIterator.previousIndex(); - if (f instanceof Multiplication || f instanceof Division) { - if (curIndex - 1 >= 0 && stackIterator.hasNext()) { - final Function next = process.get(curIndex + 1); - final Function prev = process.get(curIndex - 1); - stackIterator.set(f.setParameter(0, prev).setParameter(1, next)); - process.remove(curIndex + 1); - process.remove(curIndex - 1); - } else { - if (f.getParameter(0) == null || f.getParameter(1) == null) { - throw new Error(Errors.MISSING_ARGUMENTS, "There is a function at the end without any argument specified."); + if (f instanceof Multiplication || f instanceof Division) { + if (curIndex - 1 >= 0 && stackIterator.hasNext()) { + lastLoopDidSomething = true; + final Function next = process.get(curIndex + 1); + final Function prev = process.get(curIndex - 1); + stackIterator.set(f.setParameter(0, prev).setParameter(1, next)); + process.remove(curIndex + 1); + process.remove(curIndex - 1); + } else { + if (f.getParameter(0) == null || f.getParameter(1) == null) { + throw new Error(Errors.MISSING_ARGUMENTS, "There is a function at the end without any argument specified."); + } } } } - } + } while (lastLoopDidSomething); //Phase 3 - stackIterator = process.listIterator(); - while (stackIterator.hasNext()) { - final Function f = stackIterator.next(); - final int curIndex = stackIterator.previousIndex(); + do { + lastLoopDidSomething = false; + stackIterator = process.listIterator(); + while (stackIterator.hasNext()) { + final Function f = stackIterator.next(); + final int curIndex = stackIterator.previousIndex(); - if (f instanceof Sum || f instanceof Subtraction || f instanceof SumSubtraction) { - if (curIndex - 1 >= 0 && stackIterator.hasNext()) { - final Function next = process.get(curIndex + 1); - final Function prev = process.get(curIndex - 1); - stackIterator.set(f.setParameter(0, prev).setParameter(1, next)); - process.remove(curIndex + 1); - process.remove(curIndex - 1); - } else { - if (f.getParameter(0) == null || f.getParameter(1) == null) { - throw new Error(Errors.MISSING_ARGUMENTS, "There is a function at the end without any argument specified."); + if (f instanceof Sum || f instanceof Subtraction || f instanceof SumSubtraction) { + if (curIndex - 1 >= 0 && stackIterator.hasNext()) { + lastLoopDidSomething = true; + final Function next = process.get(curIndex + 1); + final Function prev = process.get(curIndex - 1); + stackIterator.set(f.setParameter(0, prev).setParameter(1, next)); + process.remove(curIndex + 1); + process.remove(curIndex - 1); + } else { + if (f.getParameter(0) == null || f.getParameter(1) == null) { + throw new Error(Errors.MISSING_ARGUMENTS, "There is a function at the end without any argument specified."); + } } } } - } + } while (lastLoopDidSomething); //Phase 4 - stackIterator = process.iterator(); - while (stackIterator.hasNext()) { - final Function f = stackIterator.next(); + do { + lastLoopDidSomething = false; + stackIterator = process.iterator(); + while (stackIterator.hasNext()) { + final Function f = stackIterator.next(); - if (f instanceof Function2Args) { + if (f instanceof Function2Args) { + } } - } + } while (lastLoopDidSomething); } private static ObjectArrayList makeFunctions(MathContext context, ObjectArrayList features) @@ -226,6 +395,12 @@ public class MathParser { process.add(new Variable(context, ((FeatureVariable) f).ch, ((FeatureVariable) f).varType)); } else if (f instanceof FeatureSum) { process.add(new Sum(context, (Function) ((FeatureDouble) f).getChild1(), (Function) ((FeatureDouble) f).getChild2())); + } else if (f instanceof FeaturePower) { + process.add(new Power(context, (Function) ((FeatureDouble) f).getChild1(), (Function) ((FeatureDouble) f).getChild2())); + } else if (f instanceof FeatureSquareRoot) { + process.add(new RootSquare(context, (Function) ((FeatureSingle) f).getChild())); + } else if (f instanceof FeatureParenthesis) { + process.add(new Expression(context, (Function) ((FeatureSingle) f).getChild())); // } else if (f instanceof FeatureSubtraction) { // process.add(new Subtraction(context, (Function) ((FeatureDouble) f).getChild1(), (Function) ((FeatureDouble) f).getChild2())); // } else if (f instanceof FeatureSumSubtraction) { @@ -321,7 +496,7 @@ public class MathParser { break; } } - if (bcf.ch == '-') { + if (bcf.ch == '-' || bcf.ch == '.') { isNumber = true; } if (isNumber) { diff --git a/src/org/warp/picalculator/math/parser/features/FeatureParenthesis.java b/src/org/warp/picalculator/math/parser/features/FeatureParenthesis.java new file mode 100644 index 00000000..67e750eb --- /dev/null +++ b/src/org/warp/picalculator/math/parser/features/FeatureParenthesis.java @@ -0,0 +1,9 @@ +package org.warp.picalculator.math.parser.features; + +public class FeatureParenthesis extends FeatureSingleImpl { + + public FeatureParenthesis(Object child) { + super(child); + } + +} diff --git a/src/org/warp/picalculator/math/parser/features/FeaturePower.java b/src/org/warp/picalculator/math/parser/features/FeaturePower.java new file mode 100644 index 00000000..5de97e33 --- /dev/null +++ b/src/org/warp/picalculator/math/parser/features/FeaturePower.java @@ -0,0 +1,11 @@ +package org.warp.picalculator.math.parser.features; + +import org.warp.picalculator.math.parser.features.interfaces.Feature; + +public class FeaturePower extends FeatureDoubleImpl { + + public FeaturePower(Object child1, Object child2) { + super(child1, child2); + } + +} diff --git a/src/org/warp/picalculator/math/parser/features/FeatureSquareRoot.java b/src/org/warp/picalculator/math/parser/features/FeatureSquareRoot.java new file mode 100644 index 00000000..95cfd6c2 --- /dev/null +++ b/src/org/warp/picalculator/math/parser/features/FeatureSquareRoot.java @@ -0,0 +1,9 @@ +package org.warp.picalculator.math.parser.features; + +public class FeatureSquareRoot extends FeatureSingleImpl { + + public FeatureSquareRoot(Object child) { + super(child); + } + +}