diff --git a/src/com/bytezone/diskbrowser/visicalc/Cell.java b/src/com/bytezone/diskbrowser/visicalc/Cell.java index 7c8b4bb..61097b5 100644 --- a/src/com/bytezone/diskbrowser/visicalc/Cell.java +++ b/src/com/bytezone/diskbrowser/visicalc/Cell.java @@ -13,10 +13,9 @@ class Cell implements Comparable private String label; private double value; - private String formula; + private String formulaText; private char format = ' '; - private int width; private char repeatingChar; private String repeat = ""; private boolean valid; @@ -27,35 +26,31 @@ class Cell implements Comparable this.address = address; } + void format (String format) + { + // /FG - general + // /FD - default + // /FI - integer + // /F$ - dollars and cents + // /FL - left justified + // /FR - right justified + // /F* - graph + if (format.startsWith ("/F")) + this.format = format.charAt (2); + else if (format.startsWith ("/-")) + { + repeatingChar = format.charAt (2); + for (int i = 0; i < 20; i++) + repeat += repeatingChar; + } + else + System.out.printf ("Unexpected format [%s]%n", format); + } + void doCommand (String command) { - // System.out.printf ("Cell command:%s%n", command); switch (command.charAt (0)) { - case '/': - if (command.charAt (1) == 'F') // format cell - { - // /FG - general - // /FD - default - // /FI - integer - // /F$ - dollars and cents - // /FL - left justified - // /FR - right justified - // /F* - graph - format = command.charAt (2); - if (command.length () > 3 && command.charAt (3) == '"') - label = command.substring (4); - } - else if (command.charAt (1) == '-') // repeating label - { - repeatingChar = command.charAt (2); - for (int i = 0; i < 20; i++) - repeat += repeatingChar; - } - else - System.out.println ("Unknown command: " + command); - break; - case '"': label = command.substring (1); break; @@ -64,7 +59,7 @@ class Cell implements Comparable if (command.matches ("^[0-9.]+$")) // contains only numbers or . this.value = Float.parseFloat (command); else - formula = command; + formulaText = command; } } @@ -80,19 +75,30 @@ class Cell implements Comparable double getValue () { - if (valid || formula == null) + if (valid || formulaText == null) return value; double result = 0.0; double interim = 0.0; - if (formula.startsWith ("@LOOKUP(")) + if (formulaText.startsWith ("@LOOKUP(")) { - Lookup lookup = new Lookup (parent, formula); + Lookup lookup = new Lookup (parent, formulaText); return lookup.getValue (); } - Matcher m = cellContents.matcher (formula); + System.out.printf ("Matching:[%s]%n", formulaText); + // [@IF(@ISERROR(BK24),0,BK24)] + // [@IF(D4=0,0,1)] + // [@IF(D4=0,0,B32+1)] + // [@IF(D4=0,0,1+(D3/100/D4)^D4-1*100)] + // [@SUM(C4...F4)] + // [+C4-@SUM(C5...C12)] + // [+D5/100/12] + // [.3*(B4+B7+B8+B9)] + // [+N12+(P12*(.2*K12+K9-O12))] + + Matcher m = cellContents.matcher (formulaText); while (m.find ()) { valid = true; @@ -112,7 +118,7 @@ class Cell implements Comparable } catch (NumberFormatException e) { - System.out.printf ("NFE: %s [%s]%n", m.group (4), formula); + System.out.printf ("NFE: %s [%s]%n", m.group (4), formulaText); } else { @@ -138,7 +144,7 @@ class Cell implements Comparable return result; } - System.out.println ("?? " + formula); + System.out.println ("?? " + formulaText); return value; } @@ -149,24 +155,22 @@ class Cell implements Comparable return label; if (repeatingChar > 0) return repeat; - if (formula != null) - if (formula.length () >= 12) - return formula.substring (0, 12); + if (formulaText != null) + if (formulaText.length () >= 12) + return formulaText.substring (0, 12); else - return formula; + return formulaText; return value + ""; } @Override public String toString () { - String value = repeatingChar == 0 ? label == null - ? formula == null ? ", Value: " + this.value : ", Formula: " + formula - : ", Label: " + label : ", Rpeat: " + repeatingChar; - String format = this.format == ' ' ? "" : ", Format: " + this.format; - // String width = this.width == 0 ? "" : ", Width: " + this.width; - // return String.format ("[Cell:%5s%s%s%s]", address, format, width, value); - return String.format ("[Cell:%5s%s%s]", address, format, value); + String value = repeatingChar == 0 + ? label == null ? formulaText == null ? ", Value : " + this.value + : ", Formula: " + formulaText : ", Label : " + label + : ", Repeat : " + repeatingChar; + return String.format ("[Cell:%5s %-2s%s]", address, format, value); } @Override diff --git a/src/com/bytezone/diskbrowser/visicalc/Lookup.java b/src/com/bytezone/diskbrowser/visicalc/Lookup.java index 572987b..4b4d60e 100644 --- a/src/com/bytezone/diskbrowser/visicalc/Lookup.java +++ b/src/com/bytezone/diskbrowser/visicalc/Lookup.java @@ -29,14 +29,21 @@ public class Lookup extends Function { // source could be a formula - @LOOKUP(.2*K8+K7,H3...H16) source = parent.getCell (new Address (sourceText)); + if (source == null) + { + System.out.println ("Null source:" + sourceText); + return 0; + } + + double sourceValue = source.getValue (); range = getRange (rangeText); Address target = null; for (Address address : range) { - System.out.printf ("%s : %s%n", source, address); + // System.out.printf ("%s : %s%n", source, address); Cell cell = parent.getCell (address); - if (cell != null && cell.getValue () > source.getValue ()) + if (cell != null && cell.getValue () > sourceValue) break; target = address; } diff --git a/src/com/bytezone/diskbrowser/visicalc/Sheet.java b/src/com/bytezone/diskbrowser/visicalc/Sheet.java index bdda32d..226a7de 100644 --- a/src/com/bytezone/diskbrowser/visicalc/Sheet.java +++ b/src/com/bytezone/diskbrowser/visicalc/Sheet.java @@ -1,7 +1,11 @@ package com.bytezone.diskbrowser.visicalc; import java.text.DecimalFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -9,20 +13,23 @@ import com.bytezone.diskbrowser.utilities.HexFormatter; public class Sheet implements Iterable { + private static char[] tokens = { '"', '@', '+' }; // label, function, formula/value private static final Pattern addressPattern = - Pattern.compile ("([A-B]?[A-Z])([0-9]{1,3}):"); + Pattern.compile ("([AB]?[A-Z])([0-9]{1,3}):"); // private static final Pattern functionPattern = Pattern // .compile ("\\(([A-B]?[A-Z])([0-9]{1,3})\\.\\.\\.([A-B]?[A-Z])([0-9]{1,3})\\)?"); // private static final Pattern addressList = Pattern.compile ("\\(([^,]+(,[^,]+)*)\\)"); private final Map sheet = new TreeMap (); - private final Map functions = new HashMap (); + // private final Map functions = new HashMap (); Cell currentCell = null; char defaultFormat; private final Map columnWidths = new TreeMap (); - int columnWidth = 12; + private int columnWidth = 12; + private char recalculation = ' '; + private char recalculationOrder = ' '; // Maximum cell = BK254 @@ -49,9 +56,9 @@ public class Sheet implements Iterable // /GF$ Global Format Currency // /GC Global Column // /GR Global - // /GRA + // /GRA Recalculation Auto // /GO Global - // /GOC + // /GOC Calculation Order - Columns first // /T Titles (HVBN) // /TH fix Horizontal Titles @@ -175,231 +182,128 @@ public class Sheet implements Iterable return ptr - offset; } - private void processLine (String command) + private void processLine (String line) { // NB no closing bracket: [>K11:@SUM(J11...F11] - if (command.isEmpty ()) + // >B10:/F$+B4+B7+B8+B9 + // >F2:/FR"INCOME + + if (line.isEmpty ()) { System.out.println ("empty command"); return; } - if (command.startsWith (">")) // GOTO cell + if (line.startsWith ("/")) { - Matcher m = addressPattern.matcher (command); - if (m.find ()) + switch (line.charAt (1)) { - Address address = new Address (m.group (1), m.group (2)); - currentCell = sheet.get (address.sortValue); - int pos = command.indexOf (':'); // end of cell address - command = command.substring (pos + 1); - - if (currentCell == null) - { - currentCell = new Cell (this, address); - if (!command.startsWith ("/GCC")) - sheet.put (currentCell.address.sortValue, currentCell); - } - } - else - System.out.printf ("Invalid cell address: %s%n", command); - } - - if (command.startsWith ("/")) // command - { - String data = command.substring (1); - char subCommand = command.charAt (1); - switch (subCommand) - { - case 'W': // Window control - // System.out.println (" Window command: " + data); + case 'W': + System.out.printf ("Skipping [%s]%n", line); break; - - case 'G': // Global command - // System.out.println (" Global command: " + data); - try + case 'G': + switch (line.charAt (2)) { - if (data.charAt (1) == 'C') - { - if (data.charAt (2) == 'C') - { - int width = Integer.parseInt (data.substring (3)); - int column = currentCell.address.column; - columnWidths.put (column, width); - } - else - columnWidth = Integer.parseInt (data.substring (2)); - } - else if (data.charAt (1) == 'F') - defaultFormat = data.charAt (2); - } - catch (NumberFormatException e) - { - System.out.printf ("NFE: %s%n", data.substring (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; } break; - - case 'T': // Set title area - // System.out.println (" Title command: " + data); + case 'X': + System.out.printf ("Skipping [%s]%n", line); break; - - case 'X': // Position cursor? - break; - default: - currentCell.doCommand (command); + System.out.printf ("Skipping [%s]%n", line); } + return; } - else if (command.startsWith ("@")) // function + + if (!line.startsWith (">")) // GOTO cell { - currentCell.doCommand (command); + System.out.printf ("Error [%s]%n", line); + return; } - else if (command.startsWith ("\"")) + + currentCell = null; + + Matcher m = addressPattern.matcher (line); + if (m.find ()) { - currentCell.doCommand (command); - } - else if (command.startsWith ("+")) - { - currentCell.doCommand (command); - } - else if (command.matches ("^[0-9.]+$")) // value - { - currentCell.doCommand (command); - } - else if (command.matches ("^[-A-Z]+$")) // label - { - currentCell.doCommand (command); + Address address = new Address (m.group (1), m.group (2)); + currentCell = sheet.get (address.sortValue); + + int pos = line.indexOf (':'); // end of cell address + line = line.substring (pos + 1); // remove address from line + + if (currentCell == null) + { + currentCell = new Cell (this, address); + if (!line.startsWith ("/G")) + sheet.put (currentCell.address.sortValue, currentCell); + } } else - currentCell.doCommand (command); // formula + { + System.out.printf ("Invalid cell address: %s%n", line); + return; + } + + assert currentCell != null; + + if (line.startsWith ("/G")) // global column widths + { + if (line.charAt (2) == 'C' && line.charAt (3) == 'C') + { + int width = Integer.parseInt (line.substring (4)); + columnWidths.put (currentCell.address.column, width); + } + else + System.out.printf ("Unknown Global:[%s]%n", line); + + return; + } + + // check for formatting commands before a token + String command = ""; + if (line.startsWith ("/")) + { + for (char token : tokens) + { + int pos = line.indexOf (token); + if (pos > 0) + { + command = line.substring (0, pos); + line = line.substring (pos); + break; + } + } + + if (line.startsWith ("/")) // no token found + { + command = line; + line = ""; + } + } + + if (true) + System.out.printf ("[%s][%-3s][%s]%n", currentCell.address, command, line); + + if (!command.isEmpty ()) + currentCell.format (command); // formatting command + if (!line.isEmpty ()) + currentCell.doCommand (line); // expression } - // private double evaluateFunction (String function) - // { - // if (functions.containsKey (function)) - // return functions.get (function); - // - // // System.out.println (function); - // double result = 0; - // - // if (function.startsWith ("@IF(")) - // { - // return result; - // } - // - // if (function.startsWith ("@LOOKUP(")) - // { - // return result; - // } - // - // // Range range = getRange (function); - // // if (range == null) - // // return result; - // - // if (function.startsWith ("@SUM(")) - // { - // // for (Address address : range) - // // result += getValue (address); - // String text = function.substring (4, function.length () - 1); - // Sum sum = new Sum (this, text); - // result = sum.getValue (); - // } - // else if (function.startsWith ("@COUNT(")) - // { - // // int count = 0; - // // for (Address address : range) - // // { - // // VisicalcCell cell = getCell (address); - // // if (cell != null && cell.hasValue () && cell.getValue () != 0.0) - // // ++count; - // // } - // // result = count; - // String text = function.substring (7, function.length () - 1); - // Count count = new Count (this, text); - // result = count.getValue (); - // } - // else if (function.startsWith ("@MIN(")) - // { - // // double min = Double.MAX_VALUE; - // // for (Address address : range) - // // if (min > getValue (address)) - // // min = getValue (address); - // String text = function.substring (5, function.length () - 1); - // Min min = new Min (this, text); - // result = min.getValue (); - // } - // else if (function.startsWith ("@MAX(")) - // { - // // double max = Double.MIN_VALUE; - // // for (Address address : range) - // // if (max < getValue (address)) - // // max = getValue (address); - // // result = max; - // String text = function.substring (5, function.length () - 1); - // Max max = new Max (this, text); - // result = max.getValue (); - // } - // else - // System.out.println ("Unimplemented function: " + function); - // - // functions.put (function, result); - // return result; - // } - - // Range getRange (String text) - // { - // Range range = null; - // Matcher m = functionPattern.matcher (text); - // while (m.find ()) - // { - // Address fromAddress = new Address (m.group (1), m.group (2)); - // Address toAddress = new Address (m.group (3), m.group (4)); - // range = new Range (fromAddress, toAddress); - // } - // - // if (range != null) - // return range; - // - // m = addressList.matcher (text); - // while (m.find ()) - // { - // String[] cells = m.group (1).split (","); - // range = new Range (cells); - // } - // - // if (range != null) - // return range; - // - // int pos = text.indexOf ("..."); - // if (pos > 0) - // { - // String from = text.substring (0, pos); - // String to = text.substring (pos + 3); - // Address fromAddress = new Address (from); - // Address toAddress = new Address (to); - // range = new Range (fromAddress, toAddress); - // } - // - // if (range != null) - // return range; - // System.out.println ("null range : " + text); - // - // return range; - // } - - // private double getValue (Address address) - // { - // Cell cell = sheet.get (address.sortValue); - // return cell == null ? 0.0 : cell.getValue (); - // } - - // private double getValue (String cellName) - // { - // Address address = new Address (cellName); - // return getValue (address); - // } - Cell getCell (Address address) { return sheet.get (address.sortValue);