moved to model package
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@352766 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
fff3eb8fc5
commit
4cb3c511f4
@ -1,647 +0,0 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
|
||||||
* The Apache Software License, Version 1.1
|
|
||||||
*
|
|
||||||
* Copyright (c) 2002 The Apache Software Foundation. All rights
|
|
||||||
* reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in
|
|
||||||
* the documentation and/or other materials provided with the
|
|
||||||
* distribution.
|
|
||||||
*
|
|
||||||
* 3. The end-user documentation included with the redistribution,
|
|
||||||
* if any, must include the following acknowledgment:
|
|
||||||
* "This product includes software developed by the
|
|
||||||
* Apache Software Foundation (http://www.apache.org/)."
|
|
||||||
* Alternately, this acknowledgment may appear in the software itself,
|
|
||||||
* if and wherever such third-party acknowledgments normally appear.
|
|
||||||
*
|
|
||||||
* 4. The names "Apache" and "Apache Software Foundation" and
|
|
||||||
* "Apache POI" must not be used to endorse or promote products
|
|
||||||
* derived from this software without prior written permission. For
|
|
||||||
* written permission, please contact apache@apache.org.
|
|
||||||
*
|
|
||||||
* 5. Products derived from this software may not be called "Apache",
|
|
||||||
* "Apache POI", nor may "Apache" appear in their name, without
|
|
||||||
* prior written permission of the Apache Software Foundation.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
||||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
|
||||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
||||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
||||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
* ====================================================================
|
|
||||||
*
|
|
||||||
* This software consists of voluntary contributions made by many
|
|
||||||
* individuals on behalf of the Apache Software Foundation. For more
|
|
||||||
* information on the Apache Software Foundation, please see
|
|
||||||
* <http://www.apache.org/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.hssf.record.formula;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Stack;
|
|
||||||
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import org.apache.poi.hssf.model.Workbook;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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> | <function>
|
|
||||||
* <function> ::= <functionName> ([expression [, expression]*])
|
|
||||||
*
|
|
||||||
* @author Avik Sengupta <avik AT Avik Sengupta DOT com>
|
|
||||||
* @author Andrew C. oliver (acoliver at apache dot org)
|
|
||||||
*/
|
|
||||||
public class FormulaParser {
|
|
||||||
|
|
||||||
public static int FORMULA_TYPE_CELL = 0;
|
|
||||||
public static int FORMULA_TYPE_SHARED = 1;
|
|
||||||
public static int FORMULA_TYPE_ARRAY =2;
|
|
||||||
public static int FORMULA_TYPE_CONDFOMRAT = 3;
|
|
||||||
public static int FORMULA_TYPE_NAMEDRANGE = 4;
|
|
||||||
|
|
||||||
private String formulaString;
|
|
||||||
private int pointer=0;
|
|
||||||
|
|
||||||
private List tokens = new java.util.Stack();
|
|
||||||
//private Stack tokens = new java.util.Stack();
|
|
||||||
private List result = new ArrayList();
|
|
||||||
private int numParen;
|
|
||||||
|
|
||||||
private static char TAB = '\t';
|
|
||||||
private static char CR = '\n';
|
|
||||||
|
|
||||||
private char Look; // Lookahead Character
|
|
||||||
|
|
||||||
private Workbook book;
|
|
||||||
|
|
||||||
|
|
||||||
/** 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
|
|
||||||
*/
|
|
||||||
public FormulaParser(String formula, Workbook book){
|
|
||||||
formulaString = formula;
|
|
||||||
pointer=0;
|
|
||||||
this.book = book;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Read New Character From Input Stream */
|
|
||||||
private void GetChar() {
|
|
||||||
Look=formulaString.charAt(pointer++);
|
|
||||||
//System.out.println("Got char: "+Look);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Report an Error */
|
|
||||||
private void Error(String s) {
|
|
||||||
System.out.println("Error: "+s);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Report Error and Halt */
|
|
||||||
private void Abort(String s) {
|
|
||||||
Error(s);
|
|
||||||
//System.exit(1); //throw exception??
|
|
||||||
throw new RuntimeException("Cannot Parse, sorry : "+s);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Report What Was Expected */
|
|
||||||
private void Expected(String s) {
|
|
||||||
Abort(s + " Expected");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Recognize an Alpha Character */
|
|
||||||
private boolean IsAlpha(char c) {
|
|
||||||
return Character.isLetter(c) || c == '$';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Recognize a Decimal Digit */
|
|
||||||
private boolean IsDigit(char c) {
|
|
||||||
//System.out.println("Checking digit for"+c);
|
|
||||||
return Character.isDigit(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Recognize an Alphanumeric */
|
|
||||||
private boolean IsAlNum(char c) {
|
|
||||||
return (IsAlpha(c) || IsDigit(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Recognize an Addop */
|
|
||||||
private boolean IsAddop( char c) {
|
|
||||||
return (c =='+' || c =='-');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Recognize White Space */
|
|
||||||
private boolean IsWhite( char c) {
|
|
||||||
return (c ==' ' || c== TAB);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Skip Over Leading White Space */
|
|
||||||
private void SkipWhite() {
|
|
||||||
while (IsWhite(Look)) {
|
|
||||||
GetChar();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Match a Specific Input Character */
|
|
||||||
private void Match(char x) {
|
|
||||||
if (Look != x) {
|
|
||||||
Expected("" + x + "");
|
|
||||||
}else {
|
|
||||||
GetChar();
|
|
||||||
SkipWhite();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Get an Identifier */
|
|
||||||
private String GetName() {
|
|
||||||
StringBuffer Token = new StringBuffer();
|
|
||||||
if (!IsAlpha(Look)) {
|
|
||||||
Expected("Name");
|
|
||||||
}
|
|
||||||
while (IsAlNum(Look)) {
|
|
||||||
Token = Token.append(Character.toUpperCase(Look));
|
|
||||||
GetChar();
|
|
||||||
}
|
|
||||||
SkipWhite();
|
|
||||||
return Token.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Get a Number */
|
|
||||||
private String GetNum() {
|
|
||||||
String Value ="";
|
|
||||||
if (!IsDigit(Look)) Expected("Integer");
|
|
||||||
while (IsDigit(Look)){
|
|
||||||
Value = Value + Look;
|
|
||||||
GetChar();
|
|
||||||
}
|
|
||||||
SkipWhite();
|
|
||||||
return Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Output a String with Tab */
|
|
||||||
private void Emit(String s){
|
|
||||||
System.out.print(TAB+s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Output a String with Tab and CRLF */
|
|
||||||
private void EmitLn(String s) {
|
|
||||||
Emit(s);
|
|
||||||
System.out.println();;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Parse and Translate a String Identifier */
|
|
||||||
private void Ident() {
|
|
||||||
String name;
|
|
||||||
name = GetName();
|
|
||||||
if (Look == '('){
|
|
||||||
//This is a function
|
|
||||||
function(name);
|
|
||||||
} else if (Look == ':') { // this is a AreaReference
|
|
||||||
String first = name;
|
|
||||||
Match(':');
|
|
||||||
String second = GetName();
|
|
||||||
tokens.add(new AreaPtg(first+":"+second));
|
|
||||||
} else if (Look == '!') {
|
|
||||||
Match('!');
|
|
||||||
String sheetName = name;
|
|
||||||
String first = GetName();
|
|
||||||
short externIdx = book.checkExternSheet(book.getSheetIndex(sheetName));
|
|
||||||
if (Look == ':') {
|
|
||||||
Match(':');
|
|
||||||
String second=GetName();
|
|
||||||
|
|
||||||
tokens.add(new Area3DPtg(first+":"+second,externIdx));
|
|
||||||
} else {
|
|
||||||
tokens.add(new Ref3DPtg(first,externIdx));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//this can be either a cell ref or a named range !!
|
|
||||||
boolean cellRef = true ; //we should probably do it with reg exp??
|
|
||||||
if (cellRef) {
|
|
||||||
tokens.add(new ReferencePtg(name));
|
|
||||||
}else {
|
|
||||||
//handle after named range is integrated!!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void function(String name) {
|
|
||||||
Match('(');
|
|
||||||
int numArgs = Arguments();
|
|
||||||
Match(')');
|
|
||||||
tokens.add(getFunction(name,(byte)numArgs));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Ptg getFunction(String name,byte numArgs) {
|
|
||||||
Ptg retval = null;
|
|
||||||
retval = new FuncVarPtg(name,numArgs);
|
|
||||||
/** if (numArgs == 1 && name.equals("SUM")) {
|
|
||||||
AttrPtg ptg = new AttrPtg();
|
|
||||||
ptg.setData((short)1); //sums don't care but this is what excel does.
|
|
||||||
ptg.setSum(true);
|
|
||||||
retval = ptg;
|
|
||||||
} else {
|
|
||||||
retval = new FuncVarPtg(name,numArgs);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** get arguments to a function */
|
|
||||||
private int Arguments() {
|
|
||||||
int numArgs = 0;
|
|
||||||
if (Look != ')') {
|
|
||||||
numArgs++;
|
|
||||||
Expression();
|
|
||||||
}
|
|
||||||
while (Look == ',' || Look == ';') { //TODO handle EmptyArgs
|
|
||||||
if(Look == ',') {
|
|
||||||
Match(',');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Match(';');
|
|
||||||
}
|
|
||||||
Expression();
|
|
||||||
numArgs++;
|
|
||||||
}
|
|
||||||
return numArgs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Parse and Translate a Math Factor */
|
|
||||||
private void Factor() {
|
|
||||||
if (Look == '(' ) {
|
|
||||||
Match('(');
|
|
||||||
Expression();
|
|
||||||
Match(')');
|
|
||||||
tokens.add(new ParenthesisPtg());
|
|
||||||
return;
|
|
||||||
} else if (IsAlpha(Look)){
|
|
||||||
Ident();
|
|
||||||
} else if(Look == '"') {
|
|
||||||
StringLiteral();
|
|
||||||
} else {
|
|
||||||
|
|
||||||
String number = GetNum();
|
|
||||||
if (Look=='.') {
|
|
||||||
Match('.');
|
|
||||||
String decimalPart = null;
|
|
||||||
if (IsDigit(Look)) number = number +"."+ GetNum(); //this also takes care of someone entering "1234."
|
|
||||||
tokens.add(new NumberPtg(number));
|
|
||||||
} else {
|
|
||||||
tokens.add(new IntPtg(number)); //TODO:what if the number is too big to be a short? ..add factory to return Int or Number!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StringLiteral() {
|
|
||||||
Match('"');
|
|
||||||
String name= GetName();
|
|
||||||
Match('"');
|
|
||||||
tokens.add(new StringPtg(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Recognize and Translate a Multiply */
|
|
||||||
private void Multiply(){
|
|
||||||
Match('*');
|
|
||||||
Factor();
|
|
||||||
tokens.add(new MultiplyPtg());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Recognize and Translate a Divide */
|
|
||||||
private void Divide() {
|
|
||||||
Match('/');
|
|
||||||
Factor();
|
|
||||||
tokens.add(new DividePtg());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Parse and Translate a Math Term */
|
|
||||||
private void Term(){
|
|
||||||
Factor();
|
|
||||||
while (Look == '*' || Look == '/' || Look == '^' || Look == '&') {
|
|
||||||
///TODO do we need to do anything here??
|
|
||||||
if (Look == '*') Multiply();
|
|
||||||
if (Look == '/') Divide();
|
|
||||||
if (Look == '^') Power();
|
|
||||||
if (Look == '&') Concat();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Recognize and Translate an Add */
|
|
||||||
private void Add() {
|
|
||||||
Match('+');
|
|
||||||
Term();
|
|
||||||
tokens.add(new AddPtg());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Recognize and Translate an Add */
|
|
||||||
private void Concat() {
|
|
||||||
Match('&');
|
|
||||||
Term();
|
|
||||||
tokens.add(new ConcatPtg());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Recognize and Translate a Subtract */
|
|
||||||
private void Subtract() {
|
|
||||||
Match('-');
|
|
||||||
Term();
|
|
||||||
tokens.add(new SubtractPtg());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Power() {
|
|
||||||
Match('^');
|
|
||||||
Term();
|
|
||||||
tokens.add(new PowerPtg());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Parse and Translate an Expression */
|
|
||||||
private void Expression() {
|
|
||||||
if (IsAddop(Look)) {
|
|
||||||
EmitLn("CLR D0"); //unaryAdd ptg???
|
|
||||||
} else {
|
|
||||||
Term();
|
|
||||||
}
|
|
||||||
while (IsAddop(Look)) {
|
|
||||||
if ( Look == '+' ) Add();
|
|
||||||
if (Look == '-') Subtract();
|
|
||||||
// if (Look == '*') Multiply();
|
|
||||||
// if (Look == '/') Divide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//{--------------------------------------------------------------}
|
|
||||||
//{ Parse and Translate an Assignment Statement }
|
|
||||||
/**
|
|
||||||
procedure Assignment;
|
|
||||||
var Name: string[8];
|
|
||||||
begin
|
|
||||||
Name := GetName;
|
|
||||||
Match('=');
|
|
||||||
Expression;
|
|
||||||
|
|
||||||
end;
|
|
||||||
**/
|
|
||||||
|
|
||||||
|
|
||||||
/** Initialize */
|
|
||||||
|
|
||||||
private void init() {
|
|
||||||
GetChar();
|
|
||||||
SkipWhite();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** API call to execute the parsing of the formula
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void parse() {
|
|
||||||
synchronized (tokens) {
|
|
||||||
init();
|
|
||||||
Expression();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************
|
|
||||||
* PARSER IMPLEMENTATION ENDS HERE
|
|
||||||
* EXCEL SPECIFIC METHODS BELOW
|
|
||||||
*******************************/
|
|
||||||
|
|
||||||
/** API call to retrive the array of Ptgs created as
|
|
||||||
* a result of the parsing
|
|
||||||
*/
|
|
||||||
public Ptg[] getRPNPtg() {
|
|
||||||
return getRPNPtg(FORMULA_TYPE_CELL);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Ptg[] getRPNPtg(int formulaType) {
|
|
||||||
Node node = createTree();
|
|
||||||
setRootLevelRVA(node, formulaType);
|
|
||||||
setParameterRVA(node,formulaType);
|
|
||||||
return (Ptg[]) tokens.toArray(new Ptg[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setRootLevelRVA(Node n, int formulaType) {
|
|
||||||
//Pg 16, excelfileformat.pdf @ openoffice.org
|
|
||||||
Ptg p = (Ptg) n.getValue();
|
|
||||||
if (formulaType == this.FORMULA_TYPE_NAMEDRANGE) {
|
|
||||||
if (p.getDefaultOperandClass() == Ptg.CLASS_REF) {
|
|
||||||
setClass(n,Ptg.CLASS_REF);
|
|
||||||
} else {
|
|
||||||
setClass(n,Ptg.CLASS_ARRAY);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setClass(n,Ptg.CLASS_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setParameterRVA(Node n, int formulaType) {
|
|
||||||
Ptg p = (Ptg) n.getValue();
|
|
||||||
if (p instanceof AbstractFunctionPtg) {
|
|
||||||
int numOperands = n.getNumChildren();
|
|
||||||
for (int i =0;i<n.getNumChildren();i++) {
|
|
||||||
setParameterRVA(n.getChild(i),((AbstractFunctionPtg)p).getParameterClass(i),formulaType);
|
|
||||||
if (n.getChild(i).getValue() instanceof AbstractFunctionPtg) {
|
|
||||||
setParameterRVA(n.getChild(i),formulaType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (int i =0;i<n.getNumChildren();i++) {
|
|
||||||
setParameterRVA(n.getChild(i),formulaType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void setParameterRVA(Node n, int expectedClass,int formulaType) {
|
|
||||||
Ptg p = (Ptg) n.getValue();
|
|
||||||
if (expectedClass == Ptg.CLASS_REF) { //pg 15, table 1
|
|
||||||
if (p.getDefaultOperandClass() == Ptg.CLASS_REF ) {
|
|
||||||
setClass(n, Ptg.CLASS_REF);
|
|
||||||
}
|
|
||||||
if (p.getDefaultOperandClass() == Ptg.CLASS_VALUE) {
|
|
||||||
if (formulaType==FORMULA_TYPE_CELL || formulaType == FORMULA_TYPE_SHARED) {
|
|
||||||
setClass(n,Ptg.CLASS_VALUE);
|
|
||||||
} else {
|
|
||||||
setClass(n,Ptg.CLASS_ARRAY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (p.getDefaultOperandClass() == Ptg.CLASS_ARRAY ) {
|
|
||||||
setClass(n, Ptg.CLASS_ARRAY);
|
|
||||||
}
|
|
||||||
} else if (expectedClass == Ptg.CLASS_VALUE) { //pg 15, table 2
|
|
||||||
if (formulaType == FORMULA_TYPE_NAMEDRANGE) {
|
|
||||||
setClass(n,Ptg.CLASS_ARRAY) ;
|
|
||||||
} else {
|
|
||||||
setClass(n,Ptg.CLASS_VALUE);
|
|
||||||
}
|
|
||||||
} else { //Array class, pg 16.
|
|
||||||
if (p.getDefaultOperandClass() == Ptg.CLASS_VALUE &&
|
|
||||||
(formulaType==FORMULA_TYPE_CELL || formulaType == FORMULA_TYPE_SHARED)) {
|
|
||||||
setClass(n,Ptg.CLASS_VALUE);
|
|
||||||
} else {
|
|
||||||
setClass(n,Ptg.CLASS_ARRAY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setClass(Node n, byte theClass) {
|
|
||||||
Ptg p = (Ptg) n.getValue();
|
|
||||||
if (p instanceof AbstractFunctionPtg || !(p instanceof OperationPtg)) {
|
|
||||||
p.setClass(theClass);
|
|
||||||
} else {
|
|
||||||
for (int i =0;i<n.getNumChildren();i++) {
|
|
||||||
setClass(n.getChild(i),theClass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Convience method which takes in a list then passes it to the other toFormulaString
|
|
||||||
* signature.
|
|
||||||
* @param lptgs - list of ptgs, can be null
|
|
||||||
*/
|
|
||||||
public static String toFormulaString(List lptgs) {
|
|
||||||
String retval = null;
|
|
||||||
if (lptgs == null || lptgs.size() == 0) return "#NAME";
|
|
||||||
Ptg[] ptgs = new Ptg[lptgs.size()];
|
|
||||||
ptgs = (Ptg[])lptgs.toArray(ptgs);
|
|
||||||
retval = toFormulaString(ptgs);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Static method to convert an array of Ptgs in RPN order
|
|
||||||
* to a human readable string format in infix mode
|
|
||||||
* @param ptgs - array of ptgs, can be null or empty
|
|
||||||
*/
|
|
||||||
public static String toFormulaString(Ptg[] ptgs) {
|
|
||||||
if (ptgs == null || ptgs.length == 0) return "#NAME";
|
|
||||||
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++) {
|
|
||||||
// Excel allows to have AttrPtg at position 0 (such as Blanks) which
|
|
||||||
// do not have any operands. Skip them.
|
|
||||||
if (ptgs[i] instanceof OperationPtg && i>0) {
|
|
||||||
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);
|
|
||||||
stack.push(result);
|
|
||||||
} else {
|
|
||||||
stack.push(ptgs[i].toFormulaString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (String) stack.pop(); //TODO: catch stack underflow and throw parse exception.
|
|
||||||
}
|
|
||||||
|
|
||||||
private Node createTree() {
|
|
||||||
java.util.Stack stack = new java.util.Stack();
|
|
||||||
int numPtgs = tokens.size();
|
|
||||||
OperationPtg o;
|
|
||||||
int numOperands;
|
|
||||||
Node[] operands;
|
|
||||||
for (int i=0;i<numPtgs;i++) {
|
|
||||||
if (tokens.get(i) instanceof OperationPtg) {
|
|
||||||
|
|
||||||
o = (OperationPtg) tokens.get(i);
|
|
||||||
numOperands = o.getNumberOfOperands();
|
|
||||||
operands = new Node[numOperands];
|
|
||||||
for (int j=0;j<numOperands;j++) {
|
|
||||||
operands[numOperands-j-1] = (Node) stack.pop();
|
|
||||||
}
|
|
||||||
Node result = new Node(o);
|
|
||||||
result.setChildren(operands);
|
|
||||||
stack.push(result);
|
|
||||||
} else {
|
|
||||||
stack.push(new Node((Ptg)tokens.get(i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (Node) stack.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** toString on the parser instance returns the RPN ordered list of tokens
|
|
||||||
* Useful for testing
|
|
||||||
*/
|
|
||||||
public String toString() {
|
|
||||||
StringBuffer buf = new StringBuffer();
|
|
||||||
for (int i=0;i<tokens.size();i++) {
|
|
||||||
buf.append( ( (Ptg)tokens.get(i)).toFormulaString());
|
|
||||||
buf.append(' ');
|
|
||||||
}
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
class Node {
|
|
||||||
private Ptg value=null;
|
|
||||||
private Node[] children=new Node[0];
|
|
||||||
private int numChild=0;
|
|
||||||
public Node(Ptg val) {
|
|
||||||
value = val;
|
|
||||||
}
|
|
||||||
public void setChildren(Node[] child) {children = child;numChild=child.length;}
|
|
||||||
public int getNumChildren() {return numChild;}
|
|
||||||
public Node getChild(int number) {return children[number];}
|
|
||||||
public Ptg getValue() {return value;}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user