diff --git a/src/com/bytezone/diskbrowser/visicalc/Cell.java b/src/com/bytezone/diskbrowser/visicalc/Cell.java index 327b206..417ad59 100644 --- a/src/com/bytezone/diskbrowser/visicalc/Cell.java +++ b/src/com/bytezone/diskbrowser/visicalc/Cell.java @@ -98,7 +98,12 @@ class Cell implements Comparable char operator = m.group (1).isEmpty () ? '+' : m.group (1).charAt (0); if (m.group (3) != null) // address - interim = parent.getValue (m.group (3)); + { + Address address = new Address (m.group (3)); + Cell cell = parent.getCell (address); + if (cell != null) + interim = cell.getValue (); + } else if (m.group (4) != null) // constant try { diff --git a/src/com/bytezone/diskbrowser/visicalc/Count.java b/src/com/bytezone/diskbrowser/visicalc/Count.java index ead1d32..81807d0 100644 --- a/src/com/bytezone/diskbrowser/visicalc/Count.java +++ b/src/com/bytezone/diskbrowser/visicalc/Count.java @@ -1,6 +1,6 @@ package com.bytezone.diskbrowser.visicalc; -public class Count +public class Count extends Function { Range range; Sheet parent; @@ -11,6 +11,7 @@ public class Count range = parent.getRange (text); } + @Override public double getValue () { double result = 0; diff --git a/src/com/bytezone/diskbrowser/visicalc/Expression.java b/src/com/bytezone/diskbrowser/visicalc/Expression.java new file mode 100644 index 0000000..f34d065 --- /dev/null +++ b/src/com/bytezone/diskbrowser/visicalc/Expression.java @@ -0,0 +1,192 @@ +package com.bytezone.diskbrowser.visicalc; + +import java.util.regex.Pattern; + +public class Expression +{ + // Expressions: + // - number + // - cell address + // - function + // - expression [+-*/^] expression + // - [+-=] expression + // - ( expression ) + + private static final Pattern pattern = Pattern.compile (""); + + private boolean isUnavailable; + private boolean isError; + + private boolean hasValue; + private double value; + private Function function; + private Address address; + + private Expression expression1; + private char operator; + private Expression expression2; + + private final Sheet parent; + + public Expression (Sheet parent, String input) + { + this.parent = parent; + String text = input.trim (); + + char firstChar = text.charAt (0); + if (firstChar == '-') + { + operator = '-'; + expression1 = new Expression (parent, text.substring (1)); + } + else if (firstChar == '=' || firstChar == '+') + { + expression1 = new Expression (parent, text.substring (1)); + } + else if (firstChar == '@') + { + String functionText = getFunctionText (text); + char op = getOperator (functionText, text); + if (op == ' ') + function = Function.getInstance (parent, functionText); + else if (op != '!') + setExpressions (functionText, op, text); + } + else if (firstChar == '(') + { + String bracketText = getFunctionText (text); + char op = getOperator (bracketText, text); + if (op == ' ') + expression1 = + new Expression (parent, bracketText.substring (1, bracketText.length () - 2)); + else if (op != '!') + setExpressions (bracketText, op, text); + } + else if ((firstChar >= '0' && firstChar <= '9') || firstChar == '.') + { + String numberText = getNumberText (text); + char op = getOperator (numberText, text); + if (op == ' ') + { + value = Double.parseDouble (numberText); + hasValue = true; + } + else if (op != '!') + setExpressions (numberText, op, text); + } + else if (firstChar >= 'A' && firstChar <= 'Z') + { + String addressText = getAddressText (text); + char op = getOperator (addressText, text); + if (op == ' ') + address = new Address (addressText); + else if (op != '!') + setExpressions (addressText, op, text); + } + else + System.out.printf ("Error processing [%s]%n", text); + } + + private void setExpressions (String text1, char op, String text2) + { + expression1 = new Expression (parent, text1); + operator = op; + expression2 = new Expression (parent, text2.substring (text1.length () + 2)); + } + + double getValue () + { + if (hasValue) + return value; + + if (function != null) + return function.getValue (); + + if (address != null) + return parent.getCell (address).getValue (); + + if (expression2 == null) + { + if (operator == '-') + return expression1.getValue () * -1; + return expression1.getValue (); + } + + switch (operator) + { + case ' ': + return expression1.getValue (); + case '+': + return expression1.getValue () + expression2.getValue (); + case '-': + return expression1.getValue () - expression2.getValue (); + case '*': + return expression1.getValue () * expression2.getValue (); + case '/': + return expression1.getValue () / expression2.getValue (); + case '^': + return Math.pow (expression1.getValue (), expression2.getValue ()); + } + + System.out.println ("Unresolved value"); + return 0; + } + + private String getFunctionText (String text) + { + int ptr = text.indexOf ('('); // find first left parenthesis + int depth = 1; + while (++ptr < text.length ()) // find matching right parenthesis + { + if (text.charAt (ptr) == ')') + { + --depth; + if (depth == 0) + break; + } + else if (text.charAt (ptr) == '(') + ++depth; + } + return text.substring (0, ptr); + } + + private String getNumberText (String text) + { + int ptr = 0; + while (++ptr < text.length ()) + { + char c = text.charAt (ptr); + if (c != '.' && (c < '0' || c > '9')) + break; + } + return text.substring (0, ptr); + } + + private String getAddressText (String text) + { + int ptr = 0; + while (++ptr < text.length ()) + { + char c = text.charAt (ptr); + if ((c < '0' || c > '9') && (c < 'A' || c > 'Z')) + break; + } + return text.substring (0, ptr); + } + + private char getOperator (String text1, String text2) + { + if (text1.length () == text2.length ()) + return ' '; + + char c = text2.charAt (text1.length ()); + if (c == '+' || c == '-' || c == '*' || c == '/' || c == '^') + { + setExpressions (text1, c, text2); + return c; + } + + // error + return '!'; + } +} \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/visicalc/Function.java b/src/com/bytezone/diskbrowser/visicalc/Function.java new file mode 100644 index 0000000..b05a533 --- /dev/null +++ b/src/com/bytezone/diskbrowser/visicalc/Function.java @@ -0,0 +1,26 @@ +package com.bytezone.diskbrowser.visicalc; + +public abstract class Function +{ + static Function getInstance (Sheet parent, String text) + { + if (text.startsWith ("@LOOKUP(")) + return new Lookup (parent, text); + + if (text.startsWith ("@COUNT(")) + return new Count (parent, text); + + if (text.startsWith ("@MIN(")) + return new Min (parent, text); + + if (text.startsWith ("@MAX(")) + return new Max (parent, text); + + if (text.startsWith ("@SUM(")) + return new Sum (parent, text); + + return null; + } + + abstract double getValue (); +} \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/visicalc/Lookup.java b/src/com/bytezone/diskbrowser/visicalc/Lookup.java index 97f2cf4..dfe6bcd 100644 --- a/src/com/bytezone/diskbrowser/visicalc/Lookup.java +++ b/src/com/bytezone/diskbrowser/visicalc/Lookup.java @@ -1,22 +1,21 @@ package com.bytezone.diskbrowser.visicalc; -public class Lookup +public class Lookup extends Function { Range range; Cell source; Sheet parent; boolean hasValue; + String sourceText; + String rangeText; public Lookup (Sheet parent, String text) { this.parent = parent; int pos = text.indexOf (','); - String sourceText = text.substring (8, pos); - String rangeText = text.substring (pos + 1, text.length () - 1); - - source = parent.getCell (new Address (sourceText)); - range = parent.getRange (rangeText); + sourceText = text.substring (8, pos); + rangeText = text.substring (pos + 1, text.length () - 1); } // need a mechanism to return NA and ERROR @@ -25,18 +24,28 @@ public class Lookup return hasValue; } + @Override public double getValue () { + // source could be a formula - @LOOKUP(.2*K8+K7,H3...H16) + source = parent.getCell (new Address (sourceText)); + range = parent.getRange (rangeText); + Address target = null; for (Address address : range) { - if (parent.getCell (address).getValue () > source.getValue ()) + System.out.printf ("%s : %s%n", source, address); + Cell cell = parent.getCell (address); + if (cell != null && cell.getValue () > source.getValue ()) break; target = address; } if (target != null) - return parent.getCell (target.nextColumn ()).getValue (); + if (range.isVertical ()) + return parent.getCell (target.nextColumn ()).getValue (); + else + return parent.getCell (target.nextRow ()).getValue (); return 0; } diff --git a/src/com/bytezone/diskbrowser/visicalc/Max.java b/src/com/bytezone/diskbrowser/visicalc/Max.java index d2f71db..2582142 100644 --- a/src/com/bytezone/diskbrowser/visicalc/Max.java +++ b/src/com/bytezone/diskbrowser/visicalc/Max.java @@ -1,6 +1,6 @@ package com.bytezone.diskbrowser.visicalc; -public class Max +public class Max extends Function { Range range; Sheet parent; @@ -11,6 +11,7 @@ public class Max range = parent.getRange (text); } + @Override public double getValue () { double max = Double.MIN_VALUE; diff --git a/src/com/bytezone/diskbrowser/visicalc/Min.java b/src/com/bytezone/diskbrowser/visicalc/Min.java index c1f2704..0ef570c 100644 --- a/src/com/bytezone/diskbrowser/visicalc/Min.java +++ b/src/com/bytezone/diskbrowser/visicalc/Min.java @@ -1,6 +1,6 @@ package com.bytezone.diskbrowser.visicalc; -public class Min +public class Min extends Function { Range range; Sheet parent; @@ -11,6 +11,7 @@ public class Min range = parent.getRange (text); } + @Override public double getValue () { double min = Double.MAX_VALUE; diff --git a/src/com/bytezone/diskbrowser/visicalc/Range.java b/src/com/bytezone/diskbrowser/visicalc/Range.java index c84a6b6..c273151 100644 --- a/src/com/bytezone/diskbrowser/visicalc/Range.java +++ b/src/com/bytezone/diskbrowser/visicalc/Range.java @@ -39,6 +39,20 @@ class Range implements Iterable
range.add (new Address (s)); } + boolean isHorizontal () + { + Address first = range.get (0); + Address last = range.get (range.size () - 1); + return first.row == last.row; + } + + boolean isVertical () + { + Address first = range.get (0); + Address last = range.get (range.size () - 1); + return first.column == last.column; + } + @Override public String toString () { diff --git a/src/com/bytezone/diskbrowser/visicalc/Sheet.java b/src/com/bytezone/diskbrowser/visicalc/Sheet.java index c13e949..ac75bf8 100644 --- a/src/com/bytezone/diskbrowser/visicalc/Sheet.java +++ b/src/com/bytezone/diskbrowser/visicalc/Sheet.java @@ -251,7 +251,7 @@ public class Sheet implements Iterable currentCell.doCommand (command); } } - else if (command.startsWith ("@")) + else if (command.startsWith ("@")) // function { currentCell.doCommand (command); } @@ -414,19 +414,19 @@ public class Sheet implements Iterable return range; } - public double getValue (Address address) + private double getValue (Address address) { Cell cell = sheet.get (address.sortValue); return cell == null ? 0.0 : cell.getValue (); } - public double getValue (String cellName) + private double getValue (String cellName) { Address address = new Address (cellName); return getValue (address); } - public Cell getCell (Address address) + Cell getCell (Address address) { return sheet.get (address.sortValue); } diff --git a/src/com/bytezone/diskbrowser/visicalc/Sum.java b/src/com/bytezone/diskbrowser/visicalc/Sum.java index 0b01ae7..5f7035c 100644 --- a/src/com/bytezone/diskbrowser/visicalc/Sum.java +++ b/src/com/bytezone/diskbrowser/visicalc/Sum.java @@ -1,6 +1,6 @@ package com.bytezone.diskbrowser.visicalc; -public class Sum +public class Sum extends Function { Range range; Sheet parent; @@ -11,6 +11,7 @@ public class Sum range = parent.getRange (text); } + @Override public double getValue () { double result = 0;