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:
parent
ee498b5208
commit
37175f6907
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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');
|
||||||
}
|
}
|
||||||
//{--------------------------------------------------------------}
|
|
||||||
|
|
||||||
}
|
}
|
@ -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
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user