Visicalc improvements

This commit is contained in:
Denis Molony 2017-02-25 14:56:22 +11:00
parent 176a03a786
commit 119d8472bd
25 changed files with 533 additions and 307 deletions

View File

@ -26,7 +26,7 @@ public class VisicalcFile extends AbstractFile
if (debug)
{
text.append ("\n\n");
text.append ("\n");
text.append (sheet.getLines ());
}

View File

@ -2,6 +2,8 @@ package com.bytezone.diskbrowser.visicalc;
public class Abs extends Function
{
Expression source;
Abs (Sheet parent, String text)
{
super (parent, text);
@ -10,8 +12,15 @@ public class Abs extends Function
@Override
public Value calculate ()
{
Expression exp = new Expression (parent, functionText);
value = Math.abs (exp.getValue ());
if (source == null)
{
source = new Expression (parent, functionText);
values.add (source);
}
value = Math.abs (source.getValue ());
valueType = source.getValueType ();
return this;
}
}

View File

@ -0,0 +1,17 @@
package com.bytezone.diskbrowser.visicalc;
public abstract class AbstractValue implements Value
{
protected final String typeText;
public AbstractValue (String typeText)
{
this.typeText = typeText;
}
@Override
public String getTypeText ()
{
return typeText;
}
}

View File

@ -85,10 +85,21 @@ class Address implements Comparable<Address>
return "" + (c1 == '@' ? "" : c1) + c2 + row;
}
public String getText ()
{
return text;
}
public String getDetails ()
{
return String.format ("Row:%3d Col:%3d rKey:%5d cKey:%5d", row, column, rowKey,
columnKey);
}
@Override
public String toString ()
{
return String.format ("%-4s %3d %3d %4d", text, row, column, rowKey);
return String.format ("%-6s Row:%3d Col:%3d Key:%4d", text, row, column, rowKey);
}
@Override

View File

@ -1,17 +1,30 @@
package com.bytezone.diskbrowser.visicalc;
import java.util.ArrayList;
import java.util.List;
class And extends Function
{
List<Condition> conditions = new ArrayList<Condition> ();
public And (Sheet parent, String text)
{
super (parent, text);
String list[] = text.split (",");
for (String s : list)
conditions.add (new Condition (parent, s));
}
@Override
public Value calculate ()
{
value = 0;
for (Condition condition : conditions)
if (!condition.getResult ())
{
value = 0;
return this;
}
value = 1;
return this;
}
}

View File

@ -1,17 +1,17 @@
package com.bytezone.diskbrowser.visicalc;
import java.text.DecimalFormat;
class Cell implements Comparable<Cell>, Value
class Cell extends AbstractValue implements Comparable<Cell>
{
private static final DecimalFormat nf = new DecimalFormat ("#####0.00");
// private static final DecimalFormat nf = new DecimalFormat ("#####0.00");
private static final String line = "+----------------------------------------"
+ "--------------------------------------------+";
final Address address;
private final Address address;
private final Sheet parent;
private CellType cellType;
private char cellFormat = ' ';
private final Format format = new Format ();
private char repeatingChar;
private String repeatingText;
private String repeat = "";
private String label;
@ -20,44 +20,58 @@ class Cell implements Comparable<Cell>, Value
enum CellType
{
LABEL, REPEATING_CHARACTER, VALUE
LABEL, REPEATING_CHARACTER, VALUE, EMPTY
}
public Cell (Sheet parent, Address address)
{
super ("Cell " + address.text);
this.parent = parent;
this.address = address;
cellType = CellType.VALUE; // default to VALUE, formatting may change it
value = new Number ("0.0");
cellType = CellType.EMPTY;
}
void format (String format)
Address getAddress ()
{
return address;
}
void setFormat (String formatText)
{
// /FG - general
// /FD - default
// /FI - integer
// /F$ - dollars and cents
// /F$ - two decimal places
// /FL - left justified
// /FR - right justified
// /F* - graph (histogram)
if (format.startsWith ("/F"))
this.cellFormat = format.charAt (2);
else if (format.startsWith ("/-"))
if (formatText.equals ("/TH") || formatText.equals ("/TV")) // lock titles
return;
if (formatText.startsWith ("/F"))
{
repeatingChar = format.charAt (2);
for (int i = 0; i < 20; i++)
repeat += repeatingChar;
cellType = CellType.REPEATING_CHARACTER;
format.cellFormat = formatText.charAt (2);
return;
}
else
System.out.printf ("Unexpected format [%s]%n", format);
if (formatText.startsWith ("/-"))
{
repeatingText = formatText.substring (2);
for (int i = 0; i < 20; i++)
repeat += repeatingText;
cellType = CellType.REPEATING_CHARACTER;
return;
}
System.out.printf ("Unexpected format [%s]%n", formatText);
}
void setValue (String command)
{
if (command.charAt (0) == '"')
if (!command.isEmpty () && command.charAt (0) == '"')
{
label = command.substring (1);
cellType = CellType.LABEL;
@ -80,7 +94,7 @@ class Cell implements Comparable<Cell>, Value
expressionText = "8";
// IRA.VC
if (false)
if (true)
if (address.rowKey == 66)
expressionText = "10";
else if (address.rowKey == 130)
@ -104,75 +118,37 @@ class Cell implements Comparable<Cell>, Value
expressionText = "11.9";
}
// format cell value for output
String getText (int colWidth, char defaultFormat)
{
char format = cellFormat != ' ' ? cellFormat : defaultFormat;
switch (cellType)
{
case LABEL:
return justify (label, colWidth, cellFormat);
return format.justify (label, colWidth, format.cellFormat);
case REPEATING_CHARACTER:
return justify (repeat, colWidth, format);
return format.justify (repeat, colWidth, ' ');
case EMPTY:
return "";
case VALUE:
if (value.isValueType (ValueType.ERROR) || value.isValueType (ValueType.NA)
|| value.isValueType (ValueType.NAN))
return justify (value.getText (), colWidth, format);
if (value == null)
calculate ();
return format.format (value, defaultFormat, colWidth);
Double thisValue = value.getValue ();
if (format == 'I')
{
String integerFormat = String.format ("%%%d.0f", colWidth);
return String.format (integerFormat, thisValue);
}
else if (format == '$')
{
String currencyFormat = String.format ("%%%d.%ds", colWidth, colWidth);
return String.format (currencyFormat, nf.format (thisValue));
}
else if (format == '*')
{
String graphFormat = String.format ("%%-%d.%ds", colWidth, colWidth);
// this is not finished
return String.format (graphFormat, "********************");
}
else
{
// this could be improved
String numberFormat = String.format ("%%%d.3f", colWidth + 4);
String val = String.format (numberFormat, thisValue);
while (val.endsWith ("0"))
val = ' ' + val.substring (0, val.length () - 1);
if (val.endsWith ("."))
val = ' ' + val.substring (0, val.length () - 1);
if (val.length () > colWidth)
val = val.substring (val.length () - colWidth);
return val;
}
default:
assert false;
return getText (); // not possible
}
return getText ();
}
private String justify (String text, int colWidth, char format)
{
// right justify
if (format == 'R' || format == '$' || format == 'I')
{
String labelFormat = String.format ("%%%d.%ds", colWidth, colWidth);
return (String.format (labelFormat, text));
}
// left justify
String labelFormat = String.format ("%%-%d.%ds", colWidth, colWidth);
return (String.format (labelFormat, text));
}
@Override
public double getValue ()
{
if (value == null)
calculate ();
return value.getValue ();
}
@ -185,12 +161,18 @@ class Cell implements Comparable<Cell>, Value
@Override
public String getText ()
{
if (value == null)
calculate ();
return value.getText ();
}
@Override
public boolean isValueType (ValueType type)
{
if (value == null)
calculate ();
return value.isValueType (type);
}
@ -202,21 +184,106 @@ class Cell implements Comparable<Cell>, Value
@Override
public Value calculate ()
{
if (!isCellType (CellType.VALUE))
if (value != null && value.isValueType (ValueType.VALUE))
return this;
if (expressionText == null)
if (value == null)
{
System.out.printf ("%s null expression text %n", address);
value = Function.getInstance (parent, "@ERROR");
if (expressionText == null)
expressionText = "";
Expression expression = new Expression (parent, expressionText);
value = expression.size () == 1 ? expression.get (0) : expression;
}
value.calculate ();
return this;
}
public String getDebugText ()
{
StringBuilder text = new StringBuilder ();
text.append (line);
text.append ("\n");
text.append (String.format ("| %-21s %s %17s |%n", address.getText (),
address.getDetails (), "Format : " + format.cellFormat));
text.append (line);
text.append ("\n");
switch (cellType)
{
case LABEL:
text.append (String.format ("| LABEL : %-69s |%n", label));
break;
case REPEATING_CHARACTER:
text.append (String.format ("| REPEAT : %-69s |%n", repeatingText));
break;
case EMPTY:
text.append (String.format ("| EMPTY : %-69s |%n", ""));
break;
case VALUE:
text.append (String.format ("| VALUE : %-69s |%n", expressionText));
if (value == null)
text.append (String.format ("| Value : %-69s |%n", "null"));
// else if (value instanceof Expression)
// text.append (getExpressionComponents ((Expression) value, 1));
else
text.append (getValueText (value, 0));
break;
default:
text.append ("Unknown CellType: " + cellType + "\n");
}
text.append (line);
return text.toString ();
}
private String getValueText (Value value, int depth)
{
StringBuilder text = new StringBuilder ();
String typeText = " " + value.getTypeText ();
if (value.isValueType (ValueType.VALUE))
{
String valueText = String.format ("%f", value.getValue ());
text.append (String.format ("| %-10s : %-69s |%n", typeText, valueText));
}
else
{
// should use Number or Cell or Function for simple Values
value = new Expression (parent, expressionText);
value.calculate ();
}
return this;
text.append (
String.format ("| %-10s : %-69s |%n", typeText, value.getValueType ()));
if (value instanceof Expression)
text.append (getExpressionComponents ((Expression) value, depth + 1));
else if (value instanceof Function)
text.append (getFunctionComponents ((Function) value, depth + 1));
return text.toString ();
}
private String getExpressionComponents (Expression expression, int depth)
{
StringBuilder text = new StringBuilder ();
text.append (String.format ("| Expression : %-69s |%n", expression.fullText ()));
for (Value value : expression)
text.append (getValueText (value, depth));
return text.toString ();
}
private String getFunctionComponents (Function function, int depth)
{
StringBuilder text = new StringBuilder ();
text.append (String.format ("| Function : %-69s |%n", function.fullText));
for (Value value : function)
text.append (getValueText (value, depth));
return text.toString ();
}
@Override
@ -230,11 +297,13 @@ class Cell implements Comparable<Cell>, Value
contents = "Labl: " + label;
break;
case REPEATING_CHARACTER:
contents = "Rept: " + repeatingChar;
contents = "Rept: " + repeatingText;
break;
case VALUE:
contents = "Exp : " + expressionText;
break;
case EMPTY:
contents = "Empty";
}
return String.format ("[Cell:%5s %s]", address, contents);

View File

@ -19,6 +19,7 @@ class Condition
public Condition (Sheet parent, String text)
{
this.parent = parent;
// System.out.println (text);
for (String comp : comparators)
{
@ -54,9 +55,13 @@ class Condition
conditionExpression.calculate ();
valueExpression.calculate ();
// expressions.add (conditionExpression);
// expressions.add (valueExpression);
}
if (conditionExpression.isValueType (ValueType.ERROR) || valueExpression.isValueType (ValueType.ERROR))
if (conditionExpression.isValueType (ValueType.ERROR)
|| valueExpression.isValueType (ValueType.ERROR))
return false;
double conditionResult = conditionExpression.getValue ();
@ -84,6 +89,6 @@ class Condition
public String toString ()
{
return String.format ("[cond=%s, op=%s, value=%s]", conditionText, comparator,
valueText);
valueText);
}
}

View File

@ -22,9 +22,9 @@ class Count extends Function
if (cell == null || cell.isValueType (ValueType.NA))
continue;
if (cell.isValueType (ValueType.ERROR))
if (!cell.isValueType (ValueType.VALUE))
{
valueType = ValueType.ERROR;
valueType = cell.getValueType ();
break;
}

View File

@ -5,6 +5,7 @@ class Error extends Function
public Error (Sheet parent, String text)
{
super (parent, text);
valueType = ValueType.ERROR;
}
@Override

View File

@ -1,9 +1,10 @@
package com.bytezone.diskbrowser.visicalc;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
class Expression implements Value
class Expression extends AbstractValue implements Iterable<Value>
{
// Expressions:
// number
@ -32,13 +33,15 @@ class Expression implements Value
private final List<String> operators = new ArrayList<String> ();
private final List<String> signs = new ArrayList<String> ();
private ValueType valueType;
private ValueType valueType = ValueType.VALUE;
private double value;
private String text;
public Expression (Sheet parent, String text)
{
super ("Exp");
this.text = text;
String line = checkBrackets (text);
int ptr = 0;
@ -92,7 +95,10 @@ class Expression implements Value
ptr += addressText.length ();
Cell cell = parent.getCell (addressText);
if (cell == null)
{
System.out.println ("adding NA");
values.add (Function.getInstance (parent, "@NA"));
}
else
values.add (parent.getCell (addressText));
}
@ -117,24 +123,44 @@ class Expression implements Value
}
}
assert values.size () > 0;
// assert values.size () > 0;
if (values.size () == 0)
System.out.printf ("Nothing[%s]%n", text);
}
int size ()
{
return values.size ();
}
Value get (int index)
{
return values.get (index);
}
@Override
public Value calculate ()
{
if (values.size () == 0)
{
System.out.println ("nothing to calculate: " + text);
return this;
}
try
{
Value thisValue = values.get (0);
thisValue.calculate ();
if (thisValue.isValueType (ValueType.ERROR))
value = 0;
if (thisValue.isValueType (ValueType.VALUE))
value = thisValue.getValue ();
else
{
valueType = thisValue.getValueType ();
return this;
}
value = thisValue.isValueType (ValueType.NA) ? 0 : thisValue.getValue ();
String sign = signs.get (0);
if (sign.equals ("(-)"))
value *= -1;
@ -143,14 +169,16 @@ class Expression implements Value
{
thisValue = values.get (i);
thisValue.calculate ();
if (thisValue.isValueType (ValueType.ERROR))
double nextValue = 0;
if (thisValue.isValueType (ValueType.VALUE))
nextValue = thisValue.getValue ();
else
{
valueType = thisValue.getValueType ();
return this;
}
double nextValue = thisValue.isValueType (ValueType.NA) ? 0 : thisValue.getValue ();
sign = signs.get (i);
if (sign.equals ("(-)"))
nextValue *= -1;
@ -169,13 +197,14 @@ class Expression implements Value
}
if (Double.isNaN (value))
valueType = ValueType.NAN;
valueType = ValueType.ERROR;
else
valueType = ValueType.VALUE;
}
catch (Exception e)
{
valueType = ValueType.ERROR;
e.printStackTrace ();
}
return this;
@ -187,29 +216,6 @@ class Expression implements Value
return valueType;
}
// @Override
// public boolean isValue ()
// {
// return valueType == ValueType.VALUE;
// }
//
// @Override
// public boolean isNotAvailable ()
// {
// return valueType == ValueType.NA;
// }
//
// @Override
// public boolean isNotANumber ()
// {
// return valueType == ValueType.NAN;
// }
//
// @Override
// public boolean isError ()
// {
// return valueType == ValueType.ERROR;
// }
@Override
public boolean isValueType (ValueType type)
{
@ -219,30 +225,30 @@ class Expression implements Value
@Override
public double getValue ()
{
// assert valueType == ValueType.VALUE : "Expression ValueType = " + valueType;
return value;
}
// @Override
// public String getText ()
// {
// return isNotAvailable () ? "NA" : isError () ? "Error" : isNotANumber () ? "NaN" : "";
// // return isNotAvailable () ? "NA" : isError () ? "Error" : "";
// }
@Override
public String getText ()
{
if (valueType == null && values.size () > 0)
calculate ();
if (valueType == null)
{
System.out.printf ("null valuetype in exp [%s]%n", text);
System.out.println (values.size ());
}
switch (valueType)
{
case NA:
return "NA";
case ERROR:
return "Error";
case NAN:
return "NaN";
// case NAN:
// return "NaN";
default:
return "";
return "???";
}
}
@ -264,7 +270,7 @@ class Expression implements Value
if (rightBracket > leftBracket)
{
System.out.printf ("**** Unbalanced brackets: left:%d, right:%d ****%n",
leftBracket, rightBracket);
leftBracket, rightBracket);
System.out.println (input);
return "@ERROR";
}
@ -324,29 +330,28 @@ class Expression implements Value
return text.substring (0, ptr);
}
public String fullText ()
{
StringBuilder text = new StringBuilder ();
int ptr = 0;
for (Value value : values)
{
assert value != null;
text.append (signs.get (ptr));
text.append (value.getValue ());
if (ptr < operators.size ())
text.append (operators.get (ptr++));
}
return text.toString ();
}
@Override
public String toString ()
{
// StringBuilder text = new StringBuilder ();
//
// int ptr = 0;
// for (Value value : values)
// {
// assert value != null;
// text.append (signs.get (ptr));
// // value.calculate ();
// // if (value.isValue ())
// // text.append (value.getValue ());
// if (ptr < operators.size ())
// {
// // System.out.println (operators.get (ptr));
// text.append (operators.get (ptr++));
// }
// }
// // System.out.println ("finished building");
//
// return text.toString ();
return "Expression: " + text;
return "Expression : " + text;
}
public static void main (String[] args)
@ -355,4 +360,10 @@ class Expression implements Value
System.out.println (ex.getValue ());
System.out.println (ex);
}
@Override
public Iterator<Value> iterator ()
{
return values.iterator ();
}
}

View File

@ -0,0 +1,66 @@
package com.bytezone.diskbrowser.visicalc;
import java.text.DecimalFormat;
import com.bytezone.diskbrowser.visicalc.Value.ValueType;
public class Format
{
private static final DecimalFormat nf = new DecimalFormat ("#####0.00");
char cellFormat = ' ';
String format (Value value, char defaultFormat, int colWidth)
{
char formatChar = cellFormat != ' ' ? cellFormat : defaultFormat;
if (!value.isValueType (ValueType.VALUE))
{
// char formatChar = format.cellFormat != ' ' ? format.cellFormat : defaultFormat;
return justify (value.getText (), colWidth, formatChar);
}
if (formatChar == 'I')
{
String integerFormat = String.format ("%%%d.0f", colWidth);
return String.format (integerFormat, value.getValue ());
}
else if (formatChar == '$')
{
String currencyFormat = String.format ("%%%d.%ds", colWidth, colWidth);
return String.format (currencyFormat, nf.format (value.getValue ()));
}
else if (formatChar == '*')
{
String graphFormat = String.format ("%%-%d.%ds", colWidth, colWidth);
// this is not finished
return String.format (graphFormat, "********************");
}
else
{
// this could be improved
String numberFormat = String.format ("%%%d.3f", colWidth + 4);
String val = String.format (numberFormat, value.getValue ());
while (val.endsWith ("0"))
val = ' ' + val.substring (0, val.length () - 1);
if (val.endsWith ("."))
val = ' ' + val.substring (0, val.length () - 1);
if (val.length () > colWidth)
val = val.substring (val.length () - colWidth);
return val;
}
}
String justify (String text, int colWidth, char format)
{
// right justify
if (format == 'R' || format == '$' || format == 'I')
{
String labelFormat = String.format ("%%%d.%ds", colWidth, colWidth);
return (String.format (labelFormat, text));
}
// left justify
String labelFormat = String.format ("%%-%d.%ds", colWidth, colWidth);
return (String.format (labelFormat, text));
}
}

View File

@ -1,5 +1,9 @@
package com.bytezone.diskbrowser.visicalc;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
// http://www.bricklin.com/history/refcard1.htm
// Functions:
// @AVERAGE
@ -21,15 +25,19 @@ package com.bytezone.diskbrowser.visicalc;
// @TAN
// @ATAN
abstract class Function implements Value
// should Function extend Expression? should it be Iterable<Expression>?
abstract class Function extends AbstractValue implements Iterable<Value>
{
protected final Sheet parent;
protected String functionName;
protected String functionText;
protected String fullText;
protected ValueType valueType;
protected double value;
protected List<Value> values = new ArrayList<Value> ();
static Function getInstance (Sheet parent, String text)
{
if (text.charAt (0) != '@')
@ -92,7 +100,9 @@ abstract class Function implements Value
Function (Sheet parent, String text)
{
super ("Function");
this.parent = parent;
fullText = text;
// get function's parameter string
int pos = text.indexOf ('(');
@ -123,7 +133,6 @@ abstract class Function implements Value
@Override
public double getValue ()
{
assert valueType == ValueType.VALUE : "Function ValueType = " + valueType;
return value;
}
@ -136,13 +145,19 @@ abstract class Function implements Value
return "NA";
case ERROR:
return "Error";
case NAN:
return "NaN";
// case NAN:
// return "NaN";
default:
return "";
}
}
@Override
public Iterator<Value> iterator ()
{
return values.iterator ();
}
@Override
public String toString ()
{

View File

@ -12,6 +12,7 @@ class If extends Function
public If (Sheet parent, String text)
{
super (parent, text);
// System.out.println (text);
int pos1 = functionText.indexOf (',');
int pos2 = functionText.indexOf (',', pos1 + 1);
@ -27,29 +28,32 @@ class If extends Function
{
valueType = ValueType.VALUE;
// System.out.println (functionText);
if (condition.getResult ())
{
// System.out.println ("true");
if (expTrue == null)
{
expTrue = new Expression (parent, textTrue);
values.add (expTrue);
}
expTrue.calculate ();
if (expTrue.isValueType (ValueType.ERROR) || expTrue.isValueType (ValueType.NA))
if (!expTrue.isValueType (ValueType.VALUE))
valueType = expTrue.getValueType ();
else
value = expTrue.getValue ();
}
else
{
// System.out.println ("false");
if (expFalse == null)
{
expFalse = new Expression (parent, textFalse);
values.add (expFalse);
}
expFalse.calculate ();
if (expFalse.isValueType (ValueType.ERROR) || expFalse.isValueType (ValueType.NA))
if (!expFalse.isValueType (ValueType.VALUE))
valueType = expFalse.getValueType ();
else
value = expFalse.getValue ();

View File

@ -13,6 +13,7 @@ public class Int extends Function
{
Expression exp = new Expression (parent, functionText);
value = (int) exp.getValue ();
valueType = exp.getValueType ();
return this;
}
}

View File

@ -15,7 +15,7 @@ class IsError extends Function
if (cell == null)
cell = parent.getCell (functionText);
value = cell == null ? 1 : 0;
value = cell == null ? 1 : cell.isValueType (ValueType.ERROR) ? 1 : 0;
valueType = ValueType.VALUE;
return this;

View File

@ -21,7 +21,10 @@ class Lookup extends Function
public Value calculate ()
{
if (source == null)
{
source = new Expression (parent, sourceText);
values.add (source);
}
source.calculate ();
if (!source.isValueType (ValueType.VALUE))
@ -41,16 +44,16 @@ class Lookup extends Function
target = address;
}
if (target != null)
if (target == null)
valueType = ValueType.NA;
else
{
if (range.isVertical ())
value = parent.getCell (target.nextColumn ()).getValue ();
else
value = parent.getCell (target.nextRow ()).getValue ();
Address adjacentAddress =
range.isVertical () ? target.nextColumn () : target.nextRow ();
Cell adjacentCell = parent.getCell (adjacentAddress);
value = adjacentCell.getValue ();
valueType = ValueType.VALUE;
}
else
System.out.println ("Target is null!");
return this;
}

View File

@ -22,9 +22,9 @@ class Max extends Function
if (cell == null || cell.isValueType (ValueType.NA))
continue;
if (cell.isValueType (ValueType.ERROR))
if (!cell.isValueType (ValueType.VALUE))
{
valueType = ValueType.ERROR;
valueType = cell.getValueType ();
break;
}

View File

@ -22,9 +22,9 @@ class Min extends Function
if (cell == null || cell.isValueType (ValueType.NA))
continue;
if (cell.isValueType (ValueType.ERROR))
if (!cell.isValueType (ValueType.VALUE))
{
valueType = ValueType.ERROR;
valueType = cell.getValueType ();
break;
}

View File

@ -5,20 +5,9 @@ public class Na extends Function
public Na (Sheet parent, String text)
{
super (parent, text);
valueType = ValueType.NA;
}
// @Override
// public boolean isError ()
// {
// return false;
// }
//
// @Override
// public boolean isNotAvailable ()
// {
// return true;
// }
@Override
public double getValue ()
{

View File

@ -32,9 +32,9 @@ public class Npv extends Function
if (cell == null || cell.isValueType (ValueType.NA))
continue;
if (cell.isValueType (ValueType.ERROR))
if (!cell.isValueType (ValueType.VALUE))
{
valueType = ValueType.ERROR;
valueType = cell.getValueType ();
break;
}

View File

@ -1,12 +1,14 @@
package com.bytezone.diskbrowser.visicalc;
class Number implements Value
class Number extends AbstractValue
{
private double value;
private ValueType valueType;
public Number (String text)
{
super ("Constant");
try
{
value = Double.parseDouble (text);
@ -15,32 +17,10 @@ class Number implements Value
catch (NumberFormatException e)
{
valueType = ValueType.ERROR;
e.printStackTrace ();
}
}
// @Override
// public boolean isValue ()
// {
// return valueType == ValueType.VALUE;
// }
//
// @Override
// public boolean isError ()
// {
// return valueType == ValueType.ERROR;
// }
//
// @Override
// public boolean isNotAvailable ()
// {
// return valueType == ValueType.NA;
// }
//
// @Override
// public boolean isNotANumber ()
// {
// return valueType == ValueType.NAN;
// }
@Override
public boolean isValueType (ValueType type)
{
@ -59,13 +39,6 @@ class Number implements Value
return value;
}
// @Override
// public String getText ()
// {
// return isNotAvailable () ? "NA" : isError () ? "Error" : isNotANumber () ? "NaN" : "";
// // return valueType == ValueType.ERROR ? "Error" : "";
// }
@Override
public String getText ()
{
@ -75,8 +48,8 @@ class Number implements Value
return "NA";
case ERROR:
return "Error";
case NAN:
return "NaN";
// case NAN:
// return "NaN";
default:
return "";
}

View File

@ -1,15 +1,29 @@
package com.bytezone.diskbrowser.visicalc;
import java.util.ArrayList;
import java.util.List;
class Or extends Function
{
List<Condition> conditions = new ArrayList<Condition> ();
public Or (Sheet parent, String text)
{
super (parent, text);
String list[] = text.split (",");
for (String s : list)
conditions.add (new Condition (parent, s));
}
@Override
public Value calculate ()
{
for (Condition condition : conditions)
if (condition.getResult ())
{
value = 1;
return this;
}
value = 0;
return this;
}

View File

@ -8,7 +8,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.bytezone.diskbrowser.utilities.HexFormatter;
import com.bytezone.diskbrowser.visicalc.Value.ValueType;
import com.bytezone.diskbrowser.visicalc.Cell.CellType;
public class Sheet
{
@ -21,7 +21,7 @@ public class Sheet
private final Map<Integer, Cell> columnOrderCells = new TreeMap<Integer, Cell> ();
private final List<String> lines = new ArrayList<String> ();
private Cell currentCell = null;
// private Cell currentCell = null;
private char defaultFormat;
private final Map<Integer, Integer> columnWidths = new TreeMap<Integer, Integer> ();
@ -116,7 +116,7 @@ public class Sheet
/S STORAGE COMMANDS
/SS SAVE
/SL LOAD
/SL LOAD (left/right arrow to scroll through catalog)
/SD DELETES SPECIFIED FILE ON DISK
/SI INITIALIZE A DISK ON SPECIFIED DRIVE
/SQ QUITS VISICALC
@ -149,14 +149,27 @@ public class Sheet
{
int length = getLineLength (buffer, ptr);
String line = HexFormatter.getString (buffer, ptr, length);
assert !line.isEmpty ();
lines.add (line);
processLine (line);
if (line.startsWith ("/"))
doFormat (line);
else if (line.startsWith (">")) // GOTO cell
processLine (line);
else
System.out.printf ("Error [%s]%n", line);
ptr += length + 1; // +1 for end-of-line token
}
// might have to keep recalculating until nothing changes??
calculate (recalculationOrder);
calculate (recalculationOrder);
if (recalculation == 'A') // auto
{
// recalculationOrder = 'R';
// System.out.printf ("Calculation order: %s%n", recalculationOrder);
calculate (recalculationOrder);
calculate (recalculationOrder);
}
if (false)
printDebug ();
@ -166,70 +179,23 @@ public class Sheet
{
Map<Integer, Cell> cells = order == 'R' ? rowOrderCells : columnOrderCells;
for (Cell cell : cells.values ())
if (cell.isValueType (ValueType.VALUE))
if (cell.isCellType (CellType.VALUE))
cell.calculate ();
}
private int getLineLength (byte[] buffer, int offset)
{
int ptr = offset;
while (buffer[ptr] != END_OF_LINE_TOKEN) // end-of-line token
while (buffer[ptr] != END_OF_LINE_TOKEN)
ptr++;
return ptr - offset;
}
private void processLine (String line)
{
assert !line.isEmpty ();
Cell currentCell = null;
if (line.startsWith ("/"))
{
switch (line.charAt (1))
{
case 'W':
// System.out.printf ("Skipping [%s]%n", line);
break;
case 'G':
switch (line.charAt (2))
{
case 'R':
recalculation = line.charAt (3);
break;
case 'O':
recalculationOrder = line.charAt (3);
break;
case 'P':
// System.out.printf ("Skipping [%s]%n", line);
break;
case 'C':
columnWidth = Integer.parseInt (line.substring (3));
break;
case 'F':
defaultFormat = line.charAt (3);
break;
default:
System.out.printf ("Unknown global format [%s]%n", line);
break;
}
break;
case 'X':
// System.out.printf ("Skipping [%s]%n", line);
break;
default:
System.out.printf ("Skipping [%s]%n", line);
}
return;
}
if (!line.startsWith (">")) // GOTO cell
{
System.out.printf ("Error [%s]%n", line);
return;
}
currentCell = null;
Matcher m = addressPattern.matcher (line);
Matcher m = addressPattern.matcher (line); // <cell address>:<contents>
if (m.find ())
{
Address address = new Address (m.group (1), m.group (2));
@ -258,7 +224,7 @@ public class Sheet
if (line.charAt (2) == 'C' && line.charAt (3) == 'C')
{
int width = Integer.parseInt (line.substring (4));
columnWidths.put (currentCell.address.column, width);
columnWidths.put (currentCell.getAddress ().column, width);
}
else
System.out.printf ("Unknown Global:[%s]%n", line);
@ -270,35 +236,36 @@ public class Sheet
String format = "";
while (line.startsWith ("/"))
{
String fmt = line.substring (0, FORMAT_LENGTH);
line = line.substring (FORMAT_LENGTH);
if (fmt.equals ("/TH") || fmt.equals ("/TV")) // lock titles ??
if (line.charAt (1) == '-') // repeating label
{
// ignore
currentCell.setFormat (line);
line = "";
format += line;
}
else
currentCell.format (fmt); // formatting command
format += fmt;
{
String fmt = line.substring (0, FORMAT_LENGTH);
line = line.substring (FORMAT_LENGTH);
currentCell.setFormat (fmt); // formatting command
format += fmt;
}
}
// if there is anything left it must be an expression
if (!line.isEmpty ())
currentCell.setValue (line); // expression
if (false)
System.out.printf ("[%s][%-3s][%s]%n", currentCell.address, format, line);
System.out.printf ("[%s][%-3s][%s]%n", currentCell.getAddress (), format, line);
}
private void addCell (Cell cell)
{
rowOrderCells.put (cell.address.rowKey, cell);
columnOrderCells.put (cell.address.columnKey, cell);
rowOrderCells.put (cell.getAddress ().rowKey, cell);
columnOrderCells.put (cell.getAddress ().columnKey, cell);
if (cell.address.row > highestRow)
highestRow = cell.address.row;
if (cell.address.column > highestColumn)
highestColumn = cell.address.column;
highestRow = Math.max (highestRow, cell.getAddress ().row);
highestColumn = Math.max (highestColumn, cell.getAddress ().column);
}
Cell getCell (String addressText)
@ -316,6 +283,44 @@ public class Sheet
return rowOrderCells.size ();
}
private void doFormat (String line)
{
switch (line.charAt (1))
{
case 'W':
// System.out.printf ("Skipping [%s]%n", line);
break;
case 'G':
switch (line.charAt (2))
{
case 'R':
recalculation = line.charAt (3);
break;
case 'O':
recalculationOrder = line.charAt (3);
break;
case 'P':
// System.out.printf ("Skipping [%s]%n", line);
break;
case 'C':
columnWidth = Integer.parseInt (line.substring (3));
break;
case 'F':
defaultFormat = line.charAt (3);
break;
default:
System.out.printf ("Unknown global format [%s]%n", line);
break;
}
break;
case 'X':
// System.out.printf ("Skipping [%s]%n", line);
break;
default:
System.out.printf ("Skipping [%s]%n", line);
}
}
public String getLines ()
{
StringBuilder text = new StringBuilder ();
@ -376,7 +381,7 @@ public class Sheet
for (Cell cell : rowOrderCells.values ())
{
Address cellAddress = cell.address;
Address cellAddress = cell.getAddress ();
while (lastRow < cellAddress.row)
{
++lastRow;
@ -404,6 +409,24 @@ public class Sheet
text.append (cell.getText (colWidth, defaultFormat));
}
if (debug)
{
text.append ("\n\n");
int last = -1;
for (Cell cell : columnOrderCells.values ())
{
if (last < cell.getAddress ().column)
{
text.append ("\n *** Column "
+ cell.getAddress ().column + " ***\n\n");
last = cell.getAddress ().column;
}
text.append (cell.getDebugText ());
text.append ("\n");
}
}
return text.toString ();
}
@ -417,7 +440,7 @@ public class Sheet
System.out.println ();
System.out.println ("Cells:");
for (Cell cell : rowOrderCells.values ())
System.out.println (cell);
System.out.println (cell.getDebugText ());
System.out.println ();
System.out.println ("Column widths:");

View File

@ -22,9 +22,9 @@ class Sum extends Function
if (cell == null || cell.isValueType (ValueType.NA))
continue;
if (cell.isValueType (ValueType.ERROR))
if (!cell.isValueType (ValueType.VALUE))
{
valueType = ValueType.ERROR;
valueType = cell.getValueType ();
break;
}

View File

@ -4,7 +4,7 @@ interface Value
{
enum ValueType
{
VALUE, ERROR, NA, NAN
VALUE, ERROR, NA
}
public double getValue ();
@ -16,4 +16,6 @@ interface Value
public ValueType getValueType ();
public Value calculate ();
public String getTypeText ();
}