131 lines
5.5 KiB
Java
131 lines
5.5 KiB
Java
/* ====================================================================
|
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
|
contributor license agreements. See the NOTICE file distributed with
|
|
this work for additional information regarding copyright ownership.
|
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
|
(the "License"); you may not use this file except in compliance with
|
|
the License. You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
==================================================================== */
|
|
|
|
package org.apache.poi.ss.formula;
|
|
|
|
import java.util.Stack;
|
|
|
|
import org.apache.poi.ss.formula.ptg.AttrPtg;
|
|
import org.apache.poi.ss.formula.ptg.MemAreaPtg;
|
|
import org.apache.poi.ss.formula.ptg.MemErrPtg;
|
|
import org.apache.poi.ss.formula.ptg.MemFuncPtg;
|
|
import org.apache.poi.ss.formula.ptg.OperationPtg;
|
|
import org.apache.poi.ss.formula.ptg.ParenthesisPtg;
|
|
import org.apache.poi.ss.formula.ptg.Ptg;
|
|
|
|
/**
|
|
* Common logic for rendering formulas.<br/>
|
|
*
|
|
* For POI internal use only
|
|
*
|
|
* @author Josh Micich
|
|
*/
|
|
public class FormulaRenderer {
|
|
|
|
/**
|
|
* Static method to convert an array of {@link Ptg}s in RPN order
|
|
* to a human readable string format in infix mode.
|
|
* @param book used for defined names and 3D references
|
|
* @param ptgs must not be <code>null</code>
|
|
* @return a human readable String
|
|
*/
|
|
public static String toFormulaString(FormulaRenderingWorkbook book, Ptg[] ptgs) {
|
|
if (ptgs == null || ptgs.length == 0) {
|
|
throw new IllegalArgumentException("ptgs must not be null");
|
|
}
|
|
Stack<String> stack = new Stack<String>();
|
|
|
|
for (Ptg ptg : ptgs) {
|
|
// TODO - what about MemNoMemPtg?
|
|
if(ptg instanceof MemAreaPtg || ptg instanceof MemFuncPtg || ptg instanceof MemErrPtg) {
|
|
// marks the start of a list of area expressions which will be naturally combined
|
|
// by their trailing operators (e.g. UnionPtg)
|
|
// TODO - put comment and throw exception in toFormulaString() of these classes
|
|
continue;
|
|
}
|
|
if (ptg instanceof ParenthesisPtg) {
|
|
String contents = stack.pop();
|
|
stack.push ("(" + contents + ")");
|
|
continue;
|
|
}
|
|
if (ptg instanceof AttrPtg) {
|
|
AttrPtg attrPtg = ((AttrPtg) ptg);
|
|
if (attrPtg.isOptimizedIf() || attrPtg.isOptimizedChoose() || attrPtg.isSkip()) {
|
|
continue;
|
|
}
|
|
if (attrPtg.isSpace()) {
|
|
// POI currently doesn't render spaces in formulas
|
|
continue;
|
|
// but if it ever did, care must be taken:
|
|
// tAttrSpace comes *before* the operand it applies to, which may be consistent
|
|
// with how the formula text appears but is against the RPN ordering assumed here
|
|
}
|
|
if (attrPtg.isSemiVolatile()) {
|
|
// similar to tAttrSpace - RPN is violated
|
|
continue;
|
|
}
|
|
if (attrPtg.isSum()) {
|
|
String[] operands = getOperands(stack, attrPtg.getNumberOfOperands());
|
|
stack.push(attrPtg.toFormulaString(operands));
|
|
continue;
|
|
}
|
|
throw new RuntimeException("Unexpected tAttr: " + attrPtg);
|
|
}
|
|
|
|
if (ptg instanceof WorkbookDependentFormula) {
|
|
WorkbookDependentFormula optg = (WorkbookDependentFormula) ptg;
|
|
stack.push(optg.toFormulaString(book));
|
|
continue;
|
|
}
|
|
if (! (ptg instanceof OperationPtg)) {
|
|
stack.push(ptg.toFormulaString());
|
|
continue;
|
|
}
|
|
|
|
OperationPtg o = (OperationPtg) ptg;
|
|
String[] operands = getOperands(stack, o.getNumberOfOperands());
|
|
stack.push(o.toFormulaString(operands));
|
|
}
|
|
if(stack.isEmpty()) {
|
|
// inspection of the code above reveals that every stack.pop() is followed by a
|
|
// stack.push(). So this is either an internal error or impossible.
|
|
throw new IllegalStateException("Stack underflow");
|
|
}
|
|
String result = stack.pop();
|
|
if(!stack.isEmpty()) {
|
|
// Might be caused by some tokens like AttrPtg and Mem*Ptg, which really shouldn't
|
|
// put anything on the stack
|
|
throw new IllegalStateException("too much stuff left on the stack");
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static String[] getOperands(Stack<String> stack, int nOperands) {
|
|
String[] operands = new String[nOperands];
|
|
|
|
for (int j = nOperands-1; j >= 0; j--) { // reverse iteration because args were pushed in-order
|
|
if(stack.isEmpty()) {
|
|
String msg = "Too few arguments supplied to operation. Expected (" + nOperands
|
|
+ ") operands but got (" + (nOperands - j - 1) + ")";
|
|
throw new IllegalStateException(msg);
|
|
}
|
|
operands[j] = stack.pop();
|
|
}
|
|
return operands;
|
|
}
|
|
}
|