rebuilding expressions

This commit is contained in:
Denis Molony 2016-03-07 15:37:01 +11:00
parent bc27149106
commit ed94972388
10 changed files with 267 additions and 17 deletions

View File

@ -98,7 +98,12 @@ class Cell implements Comparable<Cell>
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
{

View File

@ -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;

View File

@ -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 '!';
}
}

View File

@ -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 ();
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -39,6 +39,20 @@ class Range implements Iterable<Address>
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 ()
{

View File

@ -251,7 +251,7 @@ public class Sheet implements Iterable<Cell>
currentCell.doCommand (command);
}
}
else if (command.startsWith ("@"))
else if (command.startsWith ("@")) // function
{
currentCell.doCommand (command);
}
@ -414,19 +414,19 @@ public class Sheet implements Iterable<Cell>
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);
}

View File

@ -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;