Avik's latest formula patches

PR:
Obtained from:
Submitted by:
Reviewed by:


git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@352498 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andrew C. Oliver 2002-04-27 14:07:53 +00:00
parent ee498b5208
commit 37175f6907
13 changed files with 361 additions and 167 deletions

View File

@ -78,7 +78,7 @@ public class FormulaRecord
implements CellValueRecordInterface, Comparable implements CellValueRecordInterface, Comparable
{ {
public static final boolean EXPERIMENTAL_FORMULA_SUPPORT_ENABLED=false; public static final boolean EXPERIMENTAL_FORMULA_SUPPORT_ENABLED=true;
public static final short sid = public static final short sid =
0x06; // docs say 406...because of a bug Microsoft support site article #Q184647) 0x06; // docs say 406...because of a bug Microsoft support site article #Q184647)
@ -359,11 +359,10 @@ public class FormulaRecord
LittleEndian.putShort(data, 18 + offset, getOptions()); LittleEndian.putShort(data, 18 + offset, getOptions());
LittleEndian.putInt(data, 20 + offset, field_6_zero); LittleEndian.putInt(data, 20 + offset, field_6_zero);
LittleEndian.putShort(data, 24 + offset, getExpressionLength()); LittleEndian.putShort(data, 24 + offset, getExpressionLength());
serializePtgs(data, 26+offset);
} else { } else {
System.arraycopy(all_data,0,data,offset,all_data.length); System.arraycopy(all_data,0,data,offset,all_data.length);
} }
// serializePtgs(data, 26+offset);
return getRecordSize(); return getRecordSize();
} }

View File

@ -141,6 +141,7 @@ public class AddPtg
return buffer.toString(); return buffer.toString();
} }
public int getPrecedence() { public int getPrecedence() {
return 5; return 5;
} }
@ -148,6 +149,18 @@ public class AddPtg
public int getStringLength() { public int getStringLength() {
return 1; return 1;
} }
public String toFormulaString(String[] operands) {
StringBuffer buffer = new StringBuffer();
buffer.append(operands[ 0 ]);
buffer.append("+");
buffer.append(operands[ 1 ]);
return buffer.toString();
}
public void manipulate(List source, List results, int pos) { public void manipulate(List source, List results, int pos) {
standardBinaryManipulation(source,results,pos); standardBinaryManipulation(source,results,pos);

View File

@ -210,5 +210,12 @@ public class AttrPtg
public void manipulate(List source, List results, int pos) { public void manipulate(List source, List results, int pos) {
} }
public String toFormulaString(String[] operands) {
return "SUM(" + operands[ 0 ] + ")";
}
public int getPrecedence() {
return 1;
}
} }

View File

@ -119,7 +119,25 @@ public class DividePtg
buffer.append(operands[ 1 ].toFormulaString()); buffer.append(operands[ 1 ].toFormulaString());
return buffer.toString(); return buffer.toString();
} }
public int getPrecedence() {
return 4;
}
public int getStringLength() {
return 1;
}
public String toFormulaString(String[] operands) {
StringBuffer buffer = new StringBuffer();
buffer.append(operands[ 0 ]);
buffer.append("/");
buffer.append(operands[ 1 ]);
return buffer.toString();
}
public void manipulate(List source, List results, int pos) { public void manipulate(List source, List results, int pos) {
} }

View File

@ -60,56 +60,66 @@ import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Stack; import java.util.Stack;
import org.apache.poi.hssf.usermodel.*;
import java.io.FileOutputStream;
/** /**
* EXPERIMENTAL code to parse formulas back and forth between RPN and not * EXPERIMENTAL
* *
* @author Avik Sengupta <lists@aviksengupta.com> * @author Avik Sengupta <avik AT Avik Sengupta DOT com>
*
* This class parses a formula string into a List of tokens in RPN order
* Inspired by
* Lets Build a Compiler, by Jack Crenshaw
* BNF for the formula expression is :
* <expression> ::= <term> [<addop> <term>]*
* <term> ::= <factor> [ <mulop> <factor ]*
* <factor> ::= <number> | (<expression>) | <cellRef>
*/ */
public class FormulaParser { public class FormulaParser {
private String formulaString; private String formulaString;
private int pointer=0; private int pointer=0;
private Stack operationsList = new java.util.Stack(); private List tokens = new java.util.Stack();
private Stack operandsList = new java.util.Stack(); //private Stack tokens = new java.util.Stack();
private List result = new ArrayList(); private List result = new ArrayList();
private int numParen; private int numParen;
//{--------------------------------------------------------------}
//{ Constant Declarations }
private static char TAB = '\t'; private static char TAB = '\t';
private static char CR = '\n'; private static char CR = '\n';
//{--------------------------------------------------------------} private char Look; // Lookahead Character
//{ Variable Declarations }
private char Look; //{ Lookahead Character }
/** create the parser with the string that is to be parsed
* later call the parse() method to return ptg list in rpn order
* then call the getRPNPtg() to retrive the parse results
* This class is recommended only for single threaded use
* The parse and getPRNPtg are internally synchronized for safety, thus
* while it is safe to use in a multithreaded environment, you will get long lock waits.
*/
public FormulaParser(String formula){ public FormulaParser(String formula){
formulaString = formula; formulaString = formula;
pointer=0; pointer=0;
} }
//{--------------------------------------------------------------}
//{ Read New Character From Input Stream } /** Read New Character From Input Stream */
private void GetChar() { private void GetChar() {
Look=formulaString.charAt(pointer++); Look=formulaString.charAt(pointer++);
System.out.println("Got char: "+Look); //System.out.println("Got char: "+Look);
} }
//{--------------------------------------------------------------}
//{ Report an Error } /** Report an Error */
private void Error(String s) { private void Error(String s) {
System.out.println("Error: "+s); System.out.println("Error: "+s);
} }
//{--------------------------------------------------------------}
//{ Report Error and Halt } /** Report Error and Halt */
private void Abort(String s) { private void Abort(String s) {
Error(s); Error(s);
//System.exit(1); //throw exception?? //System.exit(1); //throw exception??
@ -117,61 +127,50 @@ public class FormulaParser {
} }
//{--------------------------------------------------------------}
//{ Report What Was Expected } /** Report What Was Expected */
private void Expected(String s) { private void Expected(String s) {
Abort(s + " Expected"); Abort(s + " Expected");
} }
//{--------------------------------------------------------------}
//{ Recognize an Alpha Character } /** Recognize an Alpha Character */
private boolean IsAlpha(char c) { private boolean IsAlpha(char c) {
return Character.isLetter(c); return Character.isLetter(c);
//return UpCase(c) in ['A'..'Z'];
} }
//{--------------------------------------------------------------}
//{ Recognize a Decimal Digit } /** Recognize a Decimal Digit */
private boolean IsDigit(char c) { private boolean IsDigit(char c) {
System.out.println("Checking digit for"+c); //System.out.println("Checking digit for"+c);
return Character.isDigit(c); return Character.isDigit(c);
//return ("0123456789".indexOf( (int) c) != 0)//c in ['0'..'9'];
} }
//{--------------------------------------------------------------}
//{ Recognize an Alphanumeric } /** Recognize an Alphanumeric */
private boolean IsAlNum(char c) { private boolean IsAlNum(char c) {
return (IsAlpha(c) || IsDigit(c)); return (IsAlpha(c) || IsDigit(c));
} }
//{--------------------------------------------------------------}
//{ Recognize an Addop } /** Recognize an Addop */
private boolean IsAddop( char c) { private boolean IsAddop( char c) {
return (c =='+' || c =='-'); return (c =='+' || c =='-');
} }
//{--------------------------------------------------------------} /** Recognize White Space */
//{ Recognize White Space }
private boolean IsWhite( char c) { private boolean IsWhite( char c) {
return (c ==' ' || c== TAB); return (c ==' ' || c== TAB);
} }
//{--------------------------------------------------------------}
//{ Skip Over Leading White Space } /** Skip Over Leading White Space */
private void SkipWhite() { private void SkipWhite() {
while (IsWhite(Look)) { while (IsWhite(Look)) {
GetChar(); GetChar();
@ -179,9 +178,8 @@ public class FormulaParser {
} }
//{--------------------------------------------------------------}
//{ Match a Specific Input Character } /** Match a Specific Input Character */
private void Match(char x) { private void Match(char x) {
if (Look != x) { if (Look != x) {
Expected("" + x + ""); Expected("" + x + "");
@ -192,9 +190,7 @@ public class FormulaParser {
} }
//{--------------------------------------------------------------} /** Get an Identifier */
//{ Get an Identifier }
private String GetName() { private String GetName() {
String Token; String Token;
Token = ""; Token = "";
@ -211,9 +207,7 @@ public class FormulaParser {
} }
//{--------------------------------------------------------------} /** Get a Number */
//{ Get a Number }
private String GetNum() { private String GetNum() {
String Value =""; String Value ="";
if (!IsDigit(Look)) Expected("Integer"); if (!IsDigit(Look)) Expected("Integer");
@ -224,139 +218,120 @@ public class FormulaParser {
SkipWhite(); SkipWhite();
return Value; return Value;
} }
/** Output a String with Tab */
//{--------------------------------------------------------------}
//{ Output a String with Tab }
private void Emit(String s){ private void Emit(String s){
System.out.print(TAB+s); System.out.print(TAB+s);
} }
/** Output a String with Tab and CRLF */
//{--------------------------------------------------------------}
//{ Output a String with Tab and CRLF }
private void EmitLn(String s) { private void EmitLn(String s) {
Emit(s); Emit(s);
System.out.println();; System.out.println();;
} }
/** Parse and Translate a Identifier */
//{---------------------------------------------------------------}
//{ Parse and Translate a Identifier }
private void Ident() { private void Ident() {
String Name; String Name;
Name = GetName(); Name = GetName();
if (Look == '('){ if (Look == '('){
//This is a function
Match('('); Match('(');
//Expression() -- add this! int numArgs = Arguments();
Match(')'); Match(')');
//this is the end of the function //this is the end of the function
//EmitLn("BSR " + Name); tokens.add(new DummyFunctionPtg(Name,numArgs));
} else { } else {
//EmitLn("MOVE " + Name + "(PC),D0b");
//this can be either a cell ref or a named range !! //this can be either a cell ref or a named range !!
boolean cellRef = true ; //we should probably do it with reg exp?? boolean cellRef = true ; //we should probably do it with reg exp??
if (cellRef) { if (cellRef) {
operationsList.add(new ValueReferencePtg()); //TODO we need to pass in Name somewhere tokens.add(new ValueReferencePtg()); //TODO we need to pass in Name somewhere??
}else { }else {
//handle after named range is integrated!! //handle after named range is integrated!!
} }
} }
} }
/** get arguments to a function */
private int Arguments() {
int numArgs = 0;
if (Look != ')') {
numArgs++;
Expression();
}
while (Look == ',') {
Match(',');
Expression();
numArgs++;
}
return numArgs;
}
/** Parse and Translate a Math Factor */
//{---------------------------------------------------------------}
//{ Parse and Translate a Math Factor }
//procedure Expression; Forward;
private void Factor() { private void Factor() {
if (Look == '(' ) { if (Look == '(' ) {
Match('('); Match('(');
operationsList.add(new ParenthesisPtg());
Expression(); Expression();
Match(')'); Match(')');
operationsList.add(new ParenthesisPtg()); tokens.add(new ParenthesisPtg());
return; return;
} else if (IsAlpha(Look)){ } else if (IsAlpha(Look)){
Ident(); Ident();
}else{ }else{
//EmitLn("MOVE #" + GetNum() + ",D0");
IntPtg p = new IntPtg(); IntPtg p = new IntPtg();
p.setValue(Short.parseShort(GetNum())); p.setValue(Short.parseShort(GetNum()));
operandsList.add(p); tokens.add(p);
} }
} }
//{--------------------------------------------------------------} /** Recognize and Translate a Multiply */
//{ Recognize and Translate a Multiply }
private void Multiply(){ private void Multiply(){
Match('*'); Match('*');
Factor(); Factor();
operationsList.add(new MultiplyPtg()); tokens.add(new MultiplyPtg());
//EmitLn("MULS (SP)+,D0");
} }
//{-------------------------------------------------------------} /** Recognize and Translate a Divide */
//{ Recognize and Translate a Divide }
private void Divide() { private void Divide() {
Match('/'); Match('/');
Factor(); Factor();
operationsList.add(new DividePtg()); tokens.add(new DividePtg());
//EmitLn("MOVE (SP)+,D1");
//EmitLn("EXS.L D0");
//EmitLn("DIVS D1,D0");
} }
//{---------------------------------------------------------------} /** Parse and Translate a Math Term */
//{ Parse and Translate a Math Term }
private void Term(){ private void Term(){
Factor(); Factor();
while (Look == '*' || Look == '/' ) { while (Look == '*' || Look == '/' ) {
//EmitLn("MOVE D0,-(SP)");
///TODO do we need to do anything here?? ///TODO do we need to do anything here??
if (Look == '*') Multiply(); if (Look == '*') Multiply();
if (Look == '/') Divide(); if (Look == '/') Divide();
} }
} }
/** Recognize and Translate an Add */
//{--------------------------------------------------------------}
//{ Recognize and Translate an Add }
private void Add() { private void Add() {
Match('+'); Match('+');
Term(); Term();
//EmitLn("ADD (SP)+,D0"); tokens.add(new AddPtg());
operationsList.add(new AddPtg());
} }
//{-------------------------------------------------------------} /** Recognize and Translate a Subtract */
//{ Recognize and Translate a Subtract }
private void Subtract() { private void Subtract() {
Match('-'); Match('-');
Term(); Term();
operationsList.add(new SubtractPtg()); tokens.add(new SubtractPtg());
//EmitLn("SUB (SP)+,D0");
//EmitLn("NEG D0");
} }
//{---------------------------------------------------------------} /** Parse and Translate an Expression */
//{ Parse and Translate an Expression }
private void Expression() { private void Expression() {
if (IsAddop(Look)) { if (IsAddop(Look)) {
EmitLn("CLR D0"); //unaryAdd ptg??? EmitLn("CLR D0"); //unaryAdd ptg???
@ -364,9 +339,10 @@ public class FormulaParser {
Term(); Term();
} }
while (IsAddop(Look)) { while (IsAddop(Look)) {
EmitLn("MOVE D0,-(SP)");
if ( Look == '+' ) Add(); if ( Look == '+' ) Add();
if (Look == '-') Subtract(); if (Look == '-') Subtract();
// if (Look == '*') Multiply();
// if (Look == '/') Divide();
} }
} }
@ -380,71 +356,104 @@ begin
Name := GetName; Name := GetName;
Match('='); Match('=');
Expression; Expression;
EmitLn('LEA ' + Name + '(PC),A0');
EmitLn('MOVE D0,(A0)')
end; end;
**/ **/
//{--------------------------------------------------------------}
//{ Initialize } /** Initialize */
private void Init() { private void Init() {
GetChar(); GetChar();
SkipWhite(); SkipWhite();
} }
/** API call to execute the parsing of the formula
*
*/
public void parse() { public void parse() {
Init(); synchronized (tokens) {
Expression(); Init();
//now tokenisation is done .. convert to RPN!! Expression();
tokenToRPN();
}
private void tokenToRPN() {
OperationPtg op;
Ptg operand;
int numOper = 0;
int numOnStack = 0;
result.add(operandsList.pop()); numOnStack++;
while (!operationsList.isEmpty()) {
op = (OperationPtg) operationsList.pop();
if (op instanceof ParenthesisPtg) {
// do something smart
}
for (numOper = op.getNumberOfOperands();numOper>0;numOper--) {
if (numOnStack==0) {
result.add(operandsList.pop());//numOnStack++;
} else {
numOnStack--;
}
}
result.add(op);
numOnStack++;
} }
} }
/** API call to retrive the array of Ptgs created as
* a result of the parsing
*/
public Ptg[] getRPNPtg() {
synchronized (tokens) {
if (tokens == null) throw new IllegalStateException("Please parse a string before trying to access the parse result");
Ptg[] retval = new Ptg[tokens.size()];
return (Ptg[]) tokens.toArray(retval);
}
}
/** Static method to convert an array of Ptgs in RPN order
* to a human readable string format in infix mode
* TODO - extra brackets might appear, but string will be semantically correct.
*/
public static String toFormulaString(Ptg[] ptgs) {
java.util.Stack stack = new java.util.Stack();
int numPtgs = ptgs.length;
OperationPtg o;
int numOperands;
String[] operands;
for (int i=0;i<numPtgs;i++) {
if (ptgs[i] instanceof OperationPtg) {
o = (OperationPtg) ptgs[i];
numOperands = o.getNumberOfOperands();
operands = new String[numOperands];
for (int j=0;j<numOperands;j++) {
operands[numOperands-j-1] = (String) stack.pop(); //TODO: catch stack underflow and throw parse exception.
}
String result = o.toFormulaString(operands);
//if (! (o instanceof DummyFunctionPtg) ) result = "("+result+")" ;
stack.push(result);
} else {
stack.push(ptgs[i].toFormulaString());
}
}
return (String) stack.pop(); //TODO: catch stack underflow and throw parse exception.
}
public String toString() { public String toString() {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
for (int i=0;i<result.size();i++) { for (int i=0;i<tokens.size();i++) {
buf.append( ( (Ptg)result.get(i)).toFormulaString()); buf.append( ( (Ptg)tokens.get(i)).toFormulaString());
buf.append(' '); buf.append(' ');
} }
return buf.toString(); return buf.toString();
} }
//{--------------------------------------------------------------} /** Main Program for testing*/
//{ Main Program for testing}
public static void main(String[] argv) { public static void main(String[] argv) {
FormulaParser fp = new FormulaParser(argv[0]+";"); FormulaParser fp = new FormulaParser(argv[0]+";");
System.out.println("\nFormula is: ");
fp.parse(); fp.parse();
System.out.println(fp.toString()); System.out.println("RPN Form is: " +fp.toString());
System.out.println("Converted Text form is : "+fp.toFormulaString(fp.getRPNPtg()));
try {
short rownum = 0;
FileOutputStream out = new FileOutputStream("test.xls");
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet();
HSSFRow r = null;
HSSFCell c = null;
r = s.createRow((short) 0);
c = r.createCell((short) 0);
c.setCellFormula(argv[0]);
wb.write(out);
out.close();
} catch (java.io.IOException ioe) {
ioe.printStackTrace();
}
//If Look <> CR then Expected('NewLine'); //If Look <> CR then Expected('NewLine');
} }
//{--------------------------------------------------------------}
} }

View File

@ -132,6 +132,16 @@ public class MultiplyPtg
return buffer.toString(); return buffer.toString();
} }
public String toFormulaString(String[] operands) {
StringBuffer buffer = new StringBuffer();
buffer.append(operands[ 0 ]);
buffer.append("*");
buffer.append(operands[ 1 ]);
return buffer.toString();
}
public void manipulate(List source, List results, int pos) { public void manipulate(List source, List results, int pos) {
standardBinaryManipulation(source, results, pos); standardBinaryManipulation(source, results, pos);
} }
@ -155,4 +165,5 @@ public class MultiplyPtg
} }
} }

View File

@ -74,6 +74,10 @@ public abstract class OperationPtg extends Ptg
public final static int TYPE_FUNCTION = 2; public final static int TYPE_FUNCTION = 2;
public abstract int getType(); public abstract int getType();
public abstract String toFormulaString(String[] operands);
public abstract int getPrecedence();
public abstract int getNumberOfOperands(); public abstract int getNumberOfOperands();

View File

@ -58,9 +58,9 @@ package org.apache.poi.hssf.record.formula;
import java.util.List; import java.util.List;
/** /**
* Dummy class, we want it only for for the parsing process * While formula tokens are stored in RPN order and thus do not need parenthesis for
* does not actually get into the file -- note by andy...there is a parenthesis PTG * precedence reasons, Parenthesis tokens ARE written to ensure that user entered
* that can be written and is sometimes! * parenthesis are displayed as-is on reading back
* *
* Avik Sengupta <lists@aviksengupta.com> * Avik Sengupta <lists@aviksengupta.com>
* Andrew C. Oliver (acoliver at apache dot org) * Andrew C. Oliver (acoliver at apache dot org)
@ -69,17 +69,18 @@ public class ParenthesisPtg
extends OperationPtg extends OperationPtg
{ {
private final static int SIZE = 1;
public final static byte sid = 0x15;
public void writeBytes(byte [] array, int offset) public void writeBytes(byte [] array, int offset)
{ {
//do nothing array[ offset + 0 ] = sid;
} }
public int getSize() public int getSize()
{ {
return 0; return SIZE;
} }
public int getType() public int getType()
@ -89,21 +90,29 @@ public class ParenthesisPtg
public int getNumberOfOperands() public int getNumberOfOperands()
{ {
return 0; return 1;
} }
public String toFormulaString() public String toFormulaString()
{ {
return "("; return "()";
} }
public String toFormulaString(Ptg [] operands) public String toFormulaString(Ptg [] operands)
{ {
return "("; return "";
} }
public void manipulate(List source, List results, int pos) { public void manipulate(List source, List results, int pos) {
} }
public String toFormulaString(String[] operands) {
return "("+operands[0]+")";
}
public int getPrecedence() {
return 2;
}
} }

View File

@ -109,6 +109,10 @@ public class PowerPtg
{ {
return "^"; return "^";
} }
public int getPrecedence() {
return 3;
}
public String toFormulaString(Ptg [] operands) public String toFormulaString(Ptg [] operands)
{ {
@ -119,8 +123,21 @@ public class PowerPtg
buffer.append(operands[ 0 ].toFormulaString()); buffer.append(operands[ 0 ].toFormulaString());
return buffer.toString(); return buffer.toString();
} }
public String toFormulaString(String[] operands) {
StringBuffer buffer = new StringBuffer();
buffer.append(operands[ 1 ]);
buffer.append("^");
buffer.append(operands[ 0 ]);
return buffer.toString();
}
public void manipulate(List source, List results, int pos) { public void manipulate(List source, List results, int pos) {
} }
} }

View File

@ -77,6 +77,54 @@ public abstract class Ptg
{ {
} }
/** convert infix order ptg list to rpn order ptg list
* @return List ptgs in RPN order
* @param infixPtgs List of ptgs in infix order
*/
public static List ptgsToRpn(List infixPtgs) {
java.util.Stack operands = new java.util.Stack();
java.util.List retval = new java.util.Stack();
java.util.ListIterator i = infixPtgs.listIterator();
Object p;
OperationPtg o ;
boolean weHaveABracket = false;
while (i.hasNext()) {
p=i.next();
if (p instanceof OperationPtg) {
if (p instanceof ParenthesisPtg) {
if (!weHaveABracket) {
operands.push(p);
weHaveABracket = true;
} else {
o = (OperationPtg) operands.pop();
while (!(o instanceof ParenthesisPtg)) {
retval.add(o);
}
weHaveABracket = false;
}
} else {
while (!operands.isEmpty() && ((OperationPtg) operands.peek()).getPrecedence() >= ((OperationPtg) p).getPrecedence() ) { //TODO handle ^ since it is right associative
retval.add(operands.pop());
}
operands.push(p);
}
} else {
retval.add(p);
}
}
while (!operands.isEmpty()) {
if (operands.peek() instanceof ParenthesisPtg ){
//throw some error
} else {
retval.add(operands.pop());
}
}
return retval;
}
/* /*

View File

@ -119,9 +119,27 @@ public class SubtractPtg
buffer.append(operands[ 1 ].toFormulaString()); buffer.append(operands[ 1 ].toFormulaString());
return buffer.toString(); return buffer.toString();
} }
public int getPrecedence() {
return 5;
}
public int getStringLength() {
return 1;
}
public String toFormulaString(String[] operands) {
StringBuffer buffer = new StringBuffer();
buffer.append(operands[ 0 ]);
buffer.append("-");
buffer.append(operands[ 1 ]);
return buffer.toString();
}
public void manipulate(List source, List results, int pos) { public void manipulate(List source, List results, int pos) {
} }
} }

View File

@ -128,8 +128,20 @@ public class ValueVariableFunctionPtg
{ {
return toFormulaString(); return toFormulaString();
} }
public String toFormulaString(String[] operands) {
return toFormulaString();
}
public void manipulate(List source, List results, int pos) { public void manipulate(List source, List results, int pos) {
} }
public int getPrecedence() {
return 1;
}
} }

View File

@ -70,6 +70,9 @@ import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.BlankRecord; import org.apache.poi.hssf.record.BlankRecord;
import org.apache.poi.hssf.record.BoolErrRecord; import org.apache.poi.hssf.record.BoolErrRecord;
import org.apache.poi.hssf.record.ExtendedFormatRecord; import org.apache.poi.hssf.record.ExtendedFormatRecord;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.FormulaParser;
import java.util.Date; import java.util.Date;
import java.util.Calendar; import java.util.Calendar;
@ -684,6 +687,32 @@ public class HSSFCell
} }
} }
public void setCellFormula(String formula) {
if (formula==null) {
setCellType(CELL_TYPE_BLANK,false);
} else {
setCellType(CELL_TYPE_FORMULA,false);
FormulaRecord rec = (FormulaRecord) record;
rec.setOptions(( short ) 2);
rec.setValue(0);
rec.setXFIndex(( short ) 0x0f);
FormulaParser fp = new FormulaParser(formula+";");
fp.parse();
Ptg[] ptg = fp.getRPNPtg();
int size = 0;
System.out.println("got Ptgs " + ptg.length);
for (int k = 0; k < ptg.length; k++) {
size += ptg[ k ].getSize();
rec.pushExpressionToken(ptg[ k ]);
}
rec.setExpressionLength(( short ) size);
//return rec;
}
}
/** /**
* get the value of the cell as a number. For strings we throw an exception. * get the value of the cell as a number. For strings we throw an exception.
* For blank cells we return a 0. * For blank cells we return a 0.