Ok, this turned out to be simple. An updated patch (against latest cvs) that
solves the parenthesis display problem i mentioned earlier. (Parenthesis Ptgs
ARE written, even tho its not required for RPN calc)
Have a good weekend folks.
Cheers
-
Avik
PS. Does the formula viewer work? I cant seem to get it to.
PPS. Anybody have any idea on section 3.12 of the openoffice excel doc
(predefined sheet formulas) which at the moment is blank? I could do with only
a few example id's so that i could test.
? formula3.patch
? src/documentation/xdocs/.nbattrs
? src/documentation/xdocs/hdf/.nbattrs
? src/documentation/xdocs/hpsf/.nbattrs
? src/documentation/xdocs/hssf/.nbattrs
? src/documentation/xdocs/news/.nbattrs
? src/documentation/xdocs/plan/.nbattrs
? src/documentation/xdocs/poifs/.nbattrs
? src/documentation/xdocs/resolutions/.nbattrs
? src/documentation/xdocs/utils/.nbattrs
? src/java/org/apache/poi/hssf/model/.nbattrs
? src/java/org/apache/poi/hssf/record/.nbattrs
? src/java/org/apache/poi/hssf/record/formula/.nbattrs
? src/java/org/apache/poi/hssf/record/formula/DummyFunctionPtg.java
? src/java/org/apache/poi/hssf/usermodel/.nbattrs
? tools/antipede/lib/temp
Index: .cvsignore
===================================================================
RCS file: /home/cvspublic/jakarta-poi/.cvsignore,v
retrieving revision 1.7
diff -u -r1.7 .cvsignore
--- .cvsignore 15 Apr 2002 08:07:45 -0000 1.7
+++ .cvsignore 26 Apr 2002 16:17:14 -0000
@@ -6,3 +6,4 @@
log*.*
*.log
build
+.nbattrs
Index: src/documentation/xdocs/plan/POI20Vision.xml
===================================================================
RCS file: /home/cvspublic/jakarta-poi/src/documentation/xdocs/plan/POI20Vision.xml,v
retrieving revision 1.5
diff -u -r1.5 POI20Vision.xml
--- src/documentation/xdocs/plan/POI20Vision.xml 6 Apr 2002 13:36:06 -0000
1.5
+++ src/documentation/xdocs/plan/POI20Vision.xml 26 Apr 2002 16:17:52 -0000
@@ -17,12 +17,12 @@
<section title="Preface">
<p>
This is the POI 2.0 cycle vision document. Although the vision
- has not changed and this document is certainly not out of date and
- the vision has not changed, the structure of the project has
+ has not changed and this document is certainly not out of date,
+ the structure of the project has
changed a bit. We're not going to change the vision document to
reflect this (however proper that may be) because it would only
involve deletion. There is no purpose in providing less
- information provided we give clarification.
+ information, provided we give clarification.
</p>
<p>
This document was created before the POI components for
@@ -94,7 +94,7 @@
</li>
<li>
Refactor HSSF for greater
- performance as well as an event-driven API for reading
+ performance as well as provide an event-driven API for reading
</li>
<li>
Extend HSSF by adding the ability to read and write formulas.
@@ -116,7 +116,7 @@
POIFSSerializer and HSSFSerializer
</li>
<li>
- Providing the create excel charts. (write only)
+ Providing the ability to create excel charts. (write only)
</li>
</ul>
</section>
Index: src/java/org/apache/poi/hssf/record/FormulaRecord.java
===================================================================
RCS file:
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/FormulaRecord.java,v
retrieving revision 1.5
diff -u -r1.5 FormulaRecord.java
--- src/java/org/apache/poi/hssf/record/FormulaRecord.java 18 Apr 2002 12:00:53
-0000 1.5
+++ src/java/org/apache/poi/hssf/record/FormulaRecord.java 26 Apr 2002 16:18:20
+-0000
@@ -78,7 +78,7 @@
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 =
0x06; // docs say 406...because of a bug Microsoft support site article
#Q184647)
@@ -359,11 +359,10 @@
LittleEndian.putShort(data, 18 + offset, getOptions());
LittleEndian.putInt(data, 20 + offset, field_6_zero);
LittleEndian.putShort(data, 24 + offset, getExpressionLength());
+ serializePtgs(data, 26+offset);
} else {
System.arraycopy(all_data,0,data,offset,all_data.length);
}
-
- // serializePtgs(data, 26+offset);
return getRecordSize();
}
Index: src/java/org/apache/poi/hssf/record/formula/AddPtg.java
===================================================================
RCS file:
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/AddPtg.java,v
retrieving revision 1.3
diff -u -r1.3 AddPtg.java
--- src/java/org/apache/poi/hssf/record/formula/AddPtg.java 23 Apr 2002 23:56:46
-0000 1.3
+++ src/java/org/apache/poi/hssf/record/formula/AddPtg.java 26 Apr 2002 16:18:32
+-0000
@@ -141,6 +141,7 @@
return buffer.toString();
}
+
public int getPrecedence() {
return 5;
}
@@ -148,6 +149,18 @@
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) {
standardBinaryManipulation(source,results,pos);
Index: src/java/org/apache/poi/hssf/record/formula/AttrPtg.java
===================================================================
RCS file:
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/AttrPtg.java,v
retrieving revision 1.2
diff -u -r1.2 AttrPtg.java
--- src/java/org/apache/poi/hssf/record/formula/AttrPtg.java 23 Apr 2002 23:56:46
-0000 1.2
+++ src/java/org/apache/poi/hssf/record/formula/AttrPtg.java 26 Apr 2002 16:18:40
+-0000
@@ -210,5 +210,12 @@
public void manipulate(List source, List results, int pos) {
}
+ public String toFormulaString(String[] operands) {
+ return "SUM(" + operands[ 0 ] + ")";
+ }
+
+ public int getPrecedence() {
+ return 1;
+ }
}
Index: src/java/org/apache/poi/hssf/record/formula/DividePtg.java
===================================================================
RCS file:
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/DividePtg.java,v
retrieving revision 1.2
diff -u -r1.2 DividePtg.java
--- src/java/org/apache/poi/hssf/record/formula/DividePtg.java 23 Apr 2002 23:56:46
-0000 1.2
+++ src/java/org/apache/poi/hssf/record/formula/DividePtg.java 26 Apr 2002 16:18:46
+-0000
@@ -119,7 +119,25 @@
buffer.append(operands[ 1 ].toFormulaString());
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) {
}
Index: src/java/org/apache/poi/hssf/record/formula/FormulaParser.java
===================================================================
RCS file:
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/FormulaParser.java,v
retrieving revision 1.1
diff -u -r1.1 FormulaParser.java
--- src/java/org/apache/poi/hssf/record/formula/FormulaParser.java 17 Apr 2002
23:06:49 -0000 1.1
+++ src/java/org/apache/poi/hssf/record/formula/FormulaParser.java 26 Apr 2002
+16:19:03 -0000
@@ -60,56 +60,66 @@
import java.util.ArrayList;
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 <avik AT Avik Sengupta DOT com>
*
- * @author Avik Sengupta <[EMAIL PROTECTED]>
+ * 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 {
private String formulaString;
private int pointer=0;
- private Stack operationsList = new java.util.Stack();
- private Stack operandsList = new java.util.Stack();
+ private List tokens = new java.util.Stack();
+ //private Stack tokens = new java.util.Stack();
private List result = new ArrayList();
private int numParen;
- //{--------------------------------------------------------------}
- //{ Constant Declarations }
-
private static char TAB = '\t';
private static char CR = '\n';
- //{--------------------------------------------------------------}
- //{ Variable Declarations }
+ private char Look; // Lookahead Character
- 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){
formulaString = formula;
pointer=0;
}
- //{--------------------------------------------------------------}
- //{ Read New Character From Input Stream }
-
+
+ /** Read New Character From Input Stream */
private void GetChar() {
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) {
System.out.println("Error: "+s);
}
- //{--------------------------------------------------------------}
- //{ Report Error and Halt }
-
+
+ /** Report Error and Halt */
private void Abort(String s) {
Error(s);
//System.exit(1); //throw exception??
@@ -117,61 +127,50 @@
}
- //{--------------------------------------------------------------}
- //{ Report What Was Expected }
-
+
+ /** Report What Was Expected */
private void Expected(String s) {
Abort(s + " Expected");
}
- //{--------------------------------------------------------------}
- //{ Recognize an Alpha Character }
-
+
+ /** Recognize an Alpha Character */
private boolean IsAlpha(char c) {
return Character.isLetter(c);
- //return UpCase(c) in ['A'..'Z'];
}
- //{--------------------------------------------------------------}
- //{ Recognize a Decimal Digit }
-
+
+ /** Recognize a Decimal Digit */
private boolean IsDigit(char c) {
- System.out.println("Checking digit for"+c);
+ //System.out.println("Checking digit for"+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) {
return (IsAlpha(c) || IsDigit(c));
}
- //{--------------------------------------------------------------}
- //{ Recognize an Addop }
-
+
+ /** Recognize an Addop */
private boolean IsAddop( char c) {
return (c =='+' || c =='-');
}
-
- //{--------------------------------------------------------------}
- //{ Recognize White Space }
-
+
+ /** Recognize White Space */
private boolean IsWhite( char c) {
return (c ==' ' || c== TAB);
}
- //{--------------------------------------------------------------}
- //{ Skip Over Leading White Space }
-
+
+ /** Skip Over Leading White Space */
private void SkipWhite() {
while (IsWhite(Look)) {
GetChar();
@@ -179,9 +178,8 @@
}
- //{--------------------------------------------------------------}
- //{ Match a Specific Input Character }
-
+
+ /** Match a Specific Input Character */
private void Match(char x) {
if (Look != x) {
Expected("" + x + "");
@@ -192,9 +190,7 @@
}
- //{--------------------------------------------------------------}
- //{ Get an Identifier }
-
+ /** Get an Identifier */
private String GetName() {
String Token;
Token = "";
@@ -211,9 +207,7 @@
}
- //{--------------------------------------------------------------}
- //{ Get a Number }
-
+ /** Get a Number */
private String GetNum() {
String Value ="";
if (!IsDigit(Look)) Expected("Integer");
@@ -224,139 +218,120 @@
SkipWhite();
return Value;
}
-
-
- //{--------------------------------------------------------------}
- //{ Output a String with Tab }
-
+
+ /** Output a String with Tab */
private void Emit(String 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) {
Emit(s);
System.out.println();;
}
-
- //{---------------------------------------------------------------}
- //{ Parse and Translate a Identifier }
-
+ /** Parse and Translate a Identifier */
private void Ident() {
String Name;
Name = GetName();
if (Look == '('){
+ //This is a function
Match('(');
- //Expression() -- add this!
+ int numArgs = Arguments();
Match(')');
//this is the end of the function
- //EmitLn("BSR " + Name);
+ tokens.add(new DummyFunctionPtg(Name,numArgs));
} else {
- //EmitLn("MOVE " + Name + "(PC),D0b");
//this can be either a cell ref or a named range !!
boolean cellRef = true ; //we should probably do it with reg exp??
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 {
//handle after named range is integrated!!
}
}
}
-
-
- //{---------------------------------------------------------------}
- //{ Parse and Translate a Math Factor }
-
- //procedure Expression; Forward;
+ /** 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 */
private void Factor() {
if (Look == '(' ) {
Match('(');
- operationsList.add(new ParenthesisPtg());
Expression();
Match(')');
- operationsList.add(new ParenthesisPtg());
+ tokens.add(new ParenthesisPtg());
return;
} else if (IsAlpha(Look)){
Ident();
}else{
- //EmitLn("MOVE #" + GetNum() + ",D0");
+
IntPtg p = new IntPtg();
p.setValue(Short.parseShort(GetNum()));
- operandsList.add(p);
+ tokens.add(p);
}
}
- //{--------------------------------------------------------------}
- //{ Recognize and Translate a Multiply }
-
+ /** Recognize and Translate a Multiply */
private void Multiply(){
Match('*');
Factor();
- operationsList.add(new MultiplyPtg());
- //EmitLn("MULS (SP)+,D0");
+ tokens.add(new MultiplyPtg());
+
}
- //{-------------------------------------------------------------}
- //{ Recognize and Translate a Divide }
-
+ /** Recognize and Translate a Divide */
private void Divide() {
Match('/');
Factor();
- operationsList.add(new DividePtg());
- //EmitLn("MOVE (SP)+,D1");
- //EmitLn("EXS.L D0");
- //EmitLn("DIVS D1,D0");
+ tokens.add(new DividePtg());
+
}
- //{---------------------------------------------------------------}
- //{ Parse and Translate a Math Term }
-
+ /** Parse and Translate a Math Term */
private void Term(){
Factor();
while (Look == '*' || Look == '/' ) {
- //EmitLn("MOVE D0,-(SP)");
///TODO do we need to do anything here??
if (Look == '*') Multiply();
if (Look == '/') Divide();
}
}
-
- //{--------------------------------------------------------------}
- //{ Recognize and Translate an Add }
-
+ /** Recognize and Translate an Add */
private void Add() {
Match('+');
Term();
- //EmitLn("ADD (SP)+,D0");
- operationsList.add(new AddPtg());
+ tokens.add(new AddPtg());
}
- //{-------------------------------------------------------------}
- //{ Recognize and Translate a Subtract }
-
+ /** Recognize and Translate a Subtract */
private void Subtract() {
Match('-');
Term();
- operationsList.add(new SubtractPtg());
- //EmitLn("SUB (SP)+,D0");
- //EmitLn("NEG D0");
+ tokens.add(new SubtractPtg());
}
- //{---------------------------------------------------------------}
- //{ Parse and Translate an Expression }
-
+ /** Parse and Translate an Expression */
private void Expression() {
if (IsAddop(Look)) {
EmitLn("CLR D0"); //unaryAdd ptg???
@@ -364,9 +339,10 @@
Term();
}
while (IsAddop(Look)) {
- EmitLn("MOVE D0,-(SP)");
if ( Look == '+' ) Add();
if (Look == '-') Subtract();
+ // if (Look == '*') Multiply();
+ // if (Look == '/') Divide();
}
}
@@ -380,71 +356,104 @@
Name := GetName;
Match('=');
Expression;
- EmitLn('LEA ' + Name + '(PC),A0');
- EmitLn('MOVE D0,(A0)')
+
end;
**/
- //{--------------------------------------------------------------}
- //{ Initialize }
+
+ /** Initialize */
private void Init() {
GetChar();
SkipWhite();
}
+ /** API call to execute the parsing of the formula
+ *
+ */
public void parse() {
- Init();
- Expression();
- //now tokenisation is done .. convert to RPN!!
- tokenToRPN();
+ synchronized (tokens) {
+ Init();
+ Expression();
+ }
}
- 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
+ /** 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());
}
-
-
- for (numOper = op.getNumberOfOperands();numOper>0;numOper--) {
- if (numOnStack==0) {
- result.add(operandsList.pop());//numOnStack++;
- } else {
- numOnStack--;
- }
- }
- result.add(op);
- numOnStack++;
}
+ return (String) stack.pop(); //TODO: catch stack underflow and throw parse
+exception.
}
-
+
public String toString() {
StringBuffer buf = new StringBuffer();
- for (int i=0;i<result.size();i++) {
- buf.append( ( (Ptg)result.get(i)).toFormulaString());
+ for (int i=0;i<tokens.size();i++) {
+ buf.append( ( (Ptg)tokens.get(i)).toFormulaString());
buf.append(' ');
}
return buf.toString();
}
- //{--------------------------------------------------------------}
- //{ Main Program for testing}
+ /** Main Program for testing*/
public static void main(String[] argv) {
FormulaParser fp = new FormulaParser(argv[0]+";");
+ System.out.println("\nFormula is: ");
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');
}
- //{--------------------------------------------------------------}
}
Index: src/java/org/apache/poi/hssf/record/formula/MultiplyPtg.java
===================================================================
RCS file:
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/MultiplyPtg.java,v
retrieving revision 1.2
diff -u -r1.2 MultiplyPtg.java
--- src/java/org/apache/poi/hssf/record/formula/MultiplyPtg.java 23 Apr 2002
23:56:46 -0000 1.2
+++ src/java/org/apache/poi/hssf/record/formula/MultiplyPtg.java 26 Apr 2002
+16:19:09 -0000
@@ -132,6 +132,16 @@
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) {
standardBinaryManipulation(source, results, pos);
}
@@ -155,4 +165,5 @@
}
+
}
Index: src/java/org/apache/poi/hssf/record/formula/OperationPtg.java
===================================================================
RCS file:
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/OperationPtg.java,v
retrieving revision 1.2
diff -u -r1.2 OperationPtg.java
--- src/java/org/apache/poi/hssf/record/formula/OperationPtg.java 23 Apr 2002
23:56:46 -0000 1.2
+++ src/java/org/apache/poi/hssf/record/formula/OperationPtg.java 26 Apr 2002
+16:19:15 -0000
@@ -74,6 +74,10 @@
public final static int TYPE_FUNCTION = 2;
public abstract int getType();
+
+ public abstract String toFormulaString(String[] operands);
+
+ public abstract int getPrecedence();
public abstract int getNumberOfOperands();
Index: src/java/org/apache/poi/hssf/record/formula/ParenthesisPtg.java
===================================================================
RCS file:
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/ParenthesisPtg.java,v
retrieving revision 1.3
diff -u -r1.3 ParenthesisPtg.java
--- src/java/org/apache/poi/hssf/record/formula/ParenthesisPtg.java 23 Apr 2002
23:56:46 -0000 1.3
+++ src/java/org/apache/poi/hssf/record/formula/ParenthesisPtg.java 26 Apr 2002
+16:19:20 -0000
@@ -58,9 +58,9 @@
import java.util.List;
/**
- * Dummy class, we want it only for for the parsing process
- * does not actually get into the file -- note by andy...there is a parenthesis PTG
- * that can be written and is sometimes!
+ * While formula tokens are stored in RPN order and thus do not need parenthesis for
+ * precedence reasons, Parenthesis tokens ARE written to ensure that user entered
+ * parenthesis are displayed as-is on reading back
*
* Avik Sengupta <[EMAIL PROTECTED]>
* Andrew C. Oliver (acoliver at apache dot org)
@@ -69,17 +69,18 @@
extends OperationPtg
{
-
+ private final static int SIZE = 1;
+ public final static byte sid = 0x15;
public void writeBytes(byte [] array, int offset)
{
- //do nothing
+ array[ offset + 0 ] = sid;
}
public int getSize()
{
- return 0;
+ return SIZE;
}
public int getType()
@@ -89,21 +90,29 @@
public int getNumberOfOperands()
{
- return 0;
+ return 1;
}
public String toFormulaString()
{
- return "(";
+ return "()";
}
public String toFormulaString(Ptg [] operands)
{
- return "(";
+ return "";
}
public void manipulate(List source, List results, int pos) {
}
+
+ public String toFormulaString(String[] operands) {
+ return "("+operands[0]+")";
+ }
+
+ public int getPrecedence() {
+ return 2;
+ }
}
Index: src/java/org/apache/poi/hssf/record/formula/PowerPtg.java
===================================================================
RCS file:
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/PowerPtg.java,v
retrieving revision 1.2
diff -u -r1.2 PowerPtg.java
--- src/java/org/apache/poi/hssf/record/formula/PowerPtg.java 23 Apr 2002 23:56:46
-0000 1.2
+++ src/java/org/apache/poi/hssf/record/formula/PowerPtg.java 26 Apr 2002 16:19:26
+-0000
@@ -109,6 +109,10 @@
{
return "^";
}
+
+ public int getPrecedence() {
+ return 3;
+ }
public String toFormulaString(Ptg [] operands)
{
@@ -119,8 +123,21 @@
buffer.append(operands[ 0 ].toFormulaString());
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) {
}
+
}
Index: src/java/org/apache/poi/hssf/record/formula/Ptg.java
===================================================================
RCS file:
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/Ptg.java,v
retrieving revision 1.4
diff -u -r1.4 Ptg.java
--- src/java/org/apache/poi/hssf/record/formula/Ptg.java 23 Apr 2002 22:24:41
-0000 1.4
+++ src/java/org/apache/poi/hssf/record/formula/Ptg.java 26 Apr 2002 16:19:37
+-0000
@@ -77,6 +77,54 @@
{
}
+ /** 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;
+ }
+
+
/*
Index: src/java/org/apache/poi/hssf/record/formula/SubtractPtg.java
===================================================================
RCS file:
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/SubtractPtg.java,v
retrieving revision 1.2
diff -u -r1.2 SubtractPtg.java
--- src/java/org/apache/poi/hssf/record/formula/SubtractPtg.java 23 Apr 2002
23:56:46 -0000 1.2
+++ src/java/org/apache/poi/hssf/record/formula/SubtractPtg.java 26 Apr 2002
+16:19:44 -0000
@@ -119,9 +119,27 @@
buffer.append(operands[ 1 ].toFormulaString());
return buffer.toString();
}
+
+ public int getPrecedence() {
+ return 5;
+ }
- public void manipulate(List source, List results, int pos) {
+ 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) {
+ }
+
}
Index: src/java/org/apache/poi/hssf/record/formula/ValueVariableFunctionPtg.java
===================================================================
RCS file:
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/ValueVariableFunctionPtg.java,v
retrieving revision 1.2
diff -u -r1.2 ValueVariableFunctionPtg.java
--- src/java/org/apache/poi/hssf/record/formula/ValueVariableFunctionPtg.java 23 Apr
2002 23:56:46 -0000 1.2
+++ src/java/org/apache/poi/hssf/record/formula/ValueVariableFunctionPtg.java 26 Apr
+2002 16:19:49 -0000
@@ -128,8 +128,20 @@
{
return toFormulaString();
}
+
+ public String toFormulaString(String[] operands) {
+ return toFormulaString();
+ }
+
+
public void manipulate(List source, List results, int pos) {
}
+ public int getPrecedence() {
+ return 1;
+ }
+
+
+
}
Index: src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
===================================================================
RCS file:
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java,v
retrieving revision 1.5
diff -u -r1.5 HSSFCell.java
--- src/java/org/apache/poi/hssf/usermodel/HSSFCell.java 15 Mar 2002 12:15:59
-0000 1.5
+++ src/java/org/apache/poi/hssf/usermodel/HSSFCell.java 26 Apr 2002 16:20:26
+-0000
@@ -70,6 +70,9 @@
import org.apache.poi.hssf.record.BlankRecord;
import org.apache.poi.hssf.record.BoolErrRecord;
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.Calendar;
@@ -684,6 +687,32 @@
}
}
+ 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.
* For blank cells we return a 0.