summaryrefslogtreecommitdiff
path: root/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula
diff options
context:
space:
mode:
Diffstat (limited to 'xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula')
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaCompiler.java271
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaHelper.java152
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaParser.java561
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaParsingException.java41
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FunctionLookup.java204
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/OperandLookup.java62
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/OperatorLookup.java73
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/ParseToken.java42
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/PrecedenceTable.java85
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/SymbolLookup.java81
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/Token.java151
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenConstants.java203
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenDecoder.java497
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenEncoder.java559
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenFactory.java118
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/UnsupportedFunctionException.java40
-rw-r--r--xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/package.html42
17 files changed, 3182 insertions, 0 deletions
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaCompiler.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaCompiler.java
new file mode 100644
index 000000000000..2e060ca0a148
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaCompiler.java
@@ -0,0 +1,271 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import java.util.*;
+import org.openoffice.xmerge.util.Debug;
+
+/**
+ * FormulaCompiler converts Calc formula string into PocketXL bytes
+ * and PocketXL formula bytes into Calc Formula strings
+ *
+ * For converting from infix to Reverse Polish (or Postfix) notation the string is
+ * converted into a vector of Tokens and then re-ordered based on a modified version
+ * of the standard Infix to RPN conversion algorithms.
+ * <pre>
+ * Infix2Rpn(tokens)
+ * while have more tokens
+ * if token is operand
+ * push to stack
+ * else if token is function, argument separater, or open bracket
+ * push token
+ * extract tokens to matching close bracket into param
+ * Infix2Rpn(param)
+ * else if token is close bracket
+ * pop from stack into result until close bracket or function
+ * else
+ * while stack.top.priority >= token.priority
+ * add stack.pop to result
+ * push token onto stack
+ * </pre>
+ * For converting from RPN to Infix the following algorithm is applied:
+ * <pre>
+ * while have more tokens
+ * if token is operand
+ * push token to stack
+ * else if token is function or operator
+ * pop from stack number of args required by token
+ * apply token to params to make expr
+ * push expr to stack
+ * return stack.pop
+ * </pre>
+ */
+public class FormulaCompiler {
+ /**
+ * Constructs a FormulaCompiler object
+ */
+ public FormulaCompiler() {
+ }
+
+ private boolean isPercent(Token pt) {
+ return pt.getTokenID() == TokenConstants.TPERCENT;
+ }
+
+ private boolean isOpenBrace(Token pt) {
+ return pt.getTokenID() == TokenConstants.TPAREN;
+ }
+
+ private boolean isCloseBrace(Token pt) {
+ return pt.getValue().compareTo(")") == 0;
+ }
+
+ private boolean isParamDelimiter(Token pt) {
+ return pt.getTokenID() == TokenConstants.TARGSEP;
+ }
+
+ private boolean isBinaryOperator(Token pt) {
+ return false;
+ }
+
+ /**
+ * Re-order into Infix format
+ * @param tokens The tokens in RPN form
+ * @return The vector of tokens re-ordered in Infix notation
+ */
+ public Vector RPN2Infix(Vector tokens) {
+ Vector infixExpr = new Vector(15);
+ ListIterator iter = tokens.listIterator();
+ Stack evalStack = new Stack();
+ Stack args = new Stack();
+
+ while (iter.hasNext()) {
+ Token pt = (Token)iter.next();
+ if (pt.isOperand()) {
+ Vector expr = new Vector(5);
+ expr.add(pt);
+ evalStack.push(expr);
+ } else if (pt.isOperator() || pt.isFunction()) {
+ args.clear();
+ for (int i=0; i< pt.getNumArgs(); i++) {
+ args.push(evalStack.pop());
+ }
+ evalStack.push(makeExpression(pt, args));
+ }
+ }
+ return (Vector)evalStack.elementAt(0);
+ }
+
+ /**
+ * Convert the infix expression to RPN. Note that open brackets are saved onto the stack to preserve the users bracketing.
+ * <p>Also note that the open bracket following functions is not pushed onto the stack - it is always implied when
+ * writing out results
+ *
+ * @param tokens The vector of tokens in Infix form
+ *
+ * @return A vector of tokens for the expression in Reverse Polish Notation order
+ */
+ public Vector infix2RPN(Vector tokens) {
+ Vector rpnExpr = new Vector(15);
+ Stack evalStack = new Stack();
+ ListIterator iter = tokens.listIterator();
+ while (iter.hasNext()) {
+ Token pt = (Token)iter.next();
+
+ if (pt.isOperand()) { //Operands are output immediately
+ rpnExpr.add(pt);
+ } else if (pt.isFunction() || isParamDelimiter(pt) || isOpenBrace(pt)) { //Extract parameters after afunction or comma
+ evalStack.push(pt);
+ if (pt.isFunction()) {
+ iter.next();
+ }
+ Vector param = extractParameter(iter);
+ Debug.log(Debug.TRACE, "Extracted parameter " + param);
+ rpnExpr.addAll(infix2RPN(param));
+ } else if (isCloseBrace(pt)) { //Pop off stack till you meet a function or an open bracket
+ Token tmpTok = null;
+ boolean bPop = true;
+ while (bPop) {
+ if (evalStack.isEmpty()) {
+ bPop = false;
+ } else {
+ tmpTok = (Token)evalStack.pop();
+ //if (!(isOpenBrace(tmpTok) || isParamDelimiter(tmpTok))) { //Don't output brackets and commas
+ if (!isParamDelimiter(tmpTok)) { //Don't output commas
+ rpnExpr.add(tmpTok);
+ }
+ if (tmpTok.isFunction() || isOpenBrace(tmpTok)) {
+ bPop = false;
+ }
+ }
+ }
+ } else {
+ if (!evalStack.isEmpty()) {
+ while (!evalStack.isEmpty() &&
+ (((Token)evalStack.peek()).getTokenPriority() >=pt.getTokenPriority())) {
+ Token topTok = (Token)evalStack.peek();
+ if (topTok.isFunction() || isOpenBrace(topTok)) {
+ break;
+ }
+ rpnExpr.add(evalStack.pop());
+ }
+ }
+ evalStack.push(pt);
+ }
+ }
+
+ while (!evalStack.isEmpty()) {
+ Token topTok = (Token)evalStack.peek();
+ if (!(isOpenBrace(topTok) || isParamDelimiter(topTok))) { //Don't output brackets and commas
+ rpnExpr.add(evalStack.pop());
+ }
+ else
+ {
+ evalStack.pop();
+ }
+ }
+ return rpnExpr;
+ }
+
+ /**
+ * Extract a parameter or bracketed sub-expression
+ * @param iter an iterator into the list
+ * @return A complete sub-expression
+ */
+ protected Vector extractParameter(ListIterator iter) {
+ Vector param = new Vector(5);
+ int subExprCount = 0;
+
+ while (iter.hasNext()) {
+ Token pt = (Token)iter.next();
+ Debug.log(Debug.TRACE, "Token is " + pt + " and subExprCount is " + subExprCount);
+ if (isOpenBrace(pt)) {
+ subExprCount++;
+ param.add(pt);
+ } else if (isCloseBrace(pt)) {
+ if (subExprCount == 0) {
+ iter.previous();
+ return param;
+ } else {
+ subExprCount--;
+ param.add(pt);
+ }
+ } else if (isParamDelimiter(pt) && (subExprCount == 0)) {
+ iter.previous();
+ return param;
+ } else {
+ param.add(pt);
+ }
+ }
+ return param;
+ }
+
+ /**
+ * Given the operator and it's operators
+ * @param pt The operator token
+ * @param args The arguments for this operator
+ * @return A correctly ordered expression
+ */
+ protected Vector makeExpression(Token pt, Stack args) {
+ Vector tmp = new Vector(5);
+ TokenFactory tf = new TokenFactory();
+ if (pt.isOperator()) {
+ if (pt.getNumArgs()==2) { //Binary operator
+ tmp.addAll((Vector)args.pop());
+ tmp.add(pt);
+ tmp.addAll((Vector)args.pop());
+ } else if (pt.getNumArgs() == 1) {
+ if(isPercent(pt)) {
+ tmp.addAll((Vector)args.elementAt(0));
+ tmp.add(pt);
+ } else {
+ tmp.add(pt);
+ tmp.addAll((Vector)args.elementAt(0));
+ }
+ if (isOpenBrace(pt)) {
+ tmp.add(tf.getOperatorToken(")",1));
+ }
+ }
+ } else if (pt.isFunction()) {
+ tmp.add(pt);
+ tmp.add(tf.getOperatorToken("(",1));
+ if (!args.isEmpty()) {
+ Vector v = (Vector)args.pop();
+ tmp.addAll(v);
+ }
+ while (!args.isEmpty()) {
+ tmp.add(tf.getOperatorToken(",",1));
+ Vector v = (Vector)args.pop();
+ tmp.addAll(v);
+
+ }
+ tmp.add(tf.getOperatorToken(")",1));
+ }
+
+ return tmp;
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaHelper.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaHelper.java
new file mode 100644
index 000000000000..208feb030f36
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaHelper.java
@@ -0,0 +1,152 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Vector;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook;
+
+/**
+ * This Helper class provides a simplified interface to conversion between PocketXL formula representation
+ * and Calc formula representation.<p>
+ * The class is used by {@link org.openoffice.xmerge.converter.xml.sxc.pexcel.Records.Formula}
+ */
+public class FormulaHelper {
+
+ private static FormulaParser parser;
+ private static FormulaCompiler compiler;
+ private static TokenEncoder encoder;
+ private static TokenDecoder decoder;
+ private boolean rangeType = false;
+ private boolean expressionType = false;
+
+ static {
+ parser = new FormulaParser();
+ compiler = new FormulaCompiler();
+ encoder = new TokenEncoder();
+ decoder = new TokenDecoder();
+ }
+
+ /**
+ * Sets the workbook cache so that global data such as
+ * <code>DefinedNames</code>, <code>Boundsheets</code> can be read
+ *
+ * @param wb Wrokbook object containing all the global data
+ */
+ public void setWorkbook(Workbook wb) {
+
+ encoder.setWorkbook(wb);
+ decoder.setWorkbook(wb);
+ parser.setWorkbook(wb);
+ }
+
+ /**
+ * Convertes a string representation of a calc formula into an array of PocketXL bytes
+ * @param formula The Formula String (e.g. 1+SUM(A1,B1))
+ *
+ * @throws UnsupportedFunctionException Thrown if a function in the formula is nto supported by Pocket Excel
+ * @throws FormulaParsingException Thrown when the formula is not well formed
+ *
+ */
+ public byte[] convertCalcToPXL(String formula) throws UnsupportedFunctionException, FormulaParsingException {
+
+ Vector parseTokens = parser.parse(formula);
+ Vector rpnTokens = compiler.infix2RPN(parseTokens);
+
+ ByteArrayOutputStream bytes = null;
+ try {
+ bytes = new ByteArrayOutputStream();
+ for (Enumeration e = rpnTokens.elements(); e.hasMoreElements();) {
+ Token t = (Token)e.nextElement();
+ bytes.write(encoder.getByte(t));
+ }
+ } catch (IOException e) {
+ }
+
+ return bytes.toByteArray();
+ }
+
+ /**
+ * Converts a PocketXL byte array into a Calc function string
+ * @param formula A byte array that contains the PocketXL bytes for a formula
+ *
+ */
+ public String convertPXLToCalc(byte[] formula) {
+
+ Vector parseTokens = decoder.getTokenVector(formula);
+ Vector infixTokens = compiler.RPN2Infix(parseTokens);
+
+ StringBuffer buff = new StringBuffer();
+ for (Enumeration e = infixTokens.elements();e.hasMoreElements();) {
+ Token t = (Token)e.nextElement();
+ buff.append(t.toString());
+ // If we are parsing a Name definition we need to know if it is of
+ // type range or expression
+ if(!t.isOperand()) {
+ expressionType = true;
+ }
+ }
+ if(!expressionType) {
+ rangeType = true;
+ }
+ return "=" + buff.toString();
+ }
+
+ /**
+ * Returns a boolean indicating whether or not the byte[] parsed is of
+ * type range. This means it contains only a cell reference and no
+ * operators. This is necessry because the syntax for range and expression
+ * types differs. This is only of interest when dealing with
+ * <code>DefinedNames</code> and not <code>Formula</code>
+ *
+ * @return a boolean true if of type range otherwise false
+ *
+ */
+ public boolean isRangeType() {
+
+ return rangeType;
+ }
+
+ /**
+ * Returns a boolean indicating whether or not the byte[] parsed is of
+ * type expression. This means it contains operators. This is necessry
+ * because the syntax for range and expression types differs. This is
+ * only of interest when dealing with <code>DefinedNames</code> and not
+ * <code>Formula</code>
+ *
+ * @return a boolean true if of type expression otherwise false
+ *
+ */
+ public boolean isExpressionType() {
+
+ return expressionType;
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaParser.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaParser.java
new file mode 100644
index 000000000000..0ab40ec53fd2
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaParser.java
@@ -0,0 +1,561 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+
+import java.util.Vector;
+
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook;
+import org.openoffice.xmerge.util.Debug;
+
+/**
+ * This is the Formula Parser based on an article written by Jack Crenshaw. It is a
+ * top down parser with some basic error handling. It handles
+ * +,-,*,/,>,<,>=,<=,=,<>, unary + and - as well as functions.
+ * The BNF notation for this parser is
+ * <pre>
+ * &lt;expression&gt; ::= &lt;unary op&gt; &lt;term&gt; [&lt;addop&gt;|&lt;logop&gt; &lt;term&gt;]
+ * &lt;term&gt; ::= &lt;factor&gt; [&lt;mulop&gt; &lt;factor&gt;]
+ * &lt;factor&gt; ::= &lt;number&gt;[%] | &lt;CellRef&gt; | &lt;QuoteString&gt; | &lt;expression&gt;
+ * </pre>
+ */
+public class FormulaParser {
+
+ private char look;
+ private String formulaStr;
+ private int index = 1;
+ private TokenFactory tokenFactory;
+ private Vector tokenVector;
+ private Workbook wb;
+
+ /**
+ * Default constructor
+ */
+ public FormulaParser() {
+
+ Debug.log(Debug.TRACE,"Creating a Formula Parser");
+ tokenFactory = new TokenFactory();
+ tokenVector = new Vector();
+ }
+
+ /**
+ *
+ */
+ public void setWorkbook(Workbook wb) {
+
+ this.wb = wb;
+ }
+
+ /**
+ * Parse method for parsing from a String to a byte[]
+ *
+ * @param formula A <code>String</code> representation of a formula
+ * starting with the '=' character
+ * @return A <code>Vector</code> containing the parsed <code>Token</code>s
+ */
+ public Vector parse(String formula) throws FormulaParsingException {
+
+ index = 1;
+ look = ' ';
+ tokenVector.clear();
+ if(formula.startsWith("=")) {
+ formulaStr = formula;
+ Debug.log(Debug.TRACE,"Creating a Formula Parser for " + formulaStr);
+ getChar();
+ expression();
+ } else {
+ throw new FormulaParsingException("No equals found!" + makeErrorString());
+ }
+ return tokenVector;
+ }
+
+ /**
+ * Identify + and - operators
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isAddOp(char c) {
+ return (c == '-') || (c == '+');
+ }
+
+ /**
+ * Determine if the current character is a multiop
+ *
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isMultiOp() {
+ return look=='*' || look =='/' || look == '^' || look == '&';
+ }
+
+ /**
+ * Identify <, >, <=, >=, =, <> using the index to find the current character(s)
+ *
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isLogicalOp() {
+ if (!isLogicalOpChar(look)) {
+ return false;
+ } else if ((index+1) >= formulaStr.length()) {//logical operators in their own right : if at end then return true
+ return true;
+ } else if (!isLogicalOpChar(formulaStr.charAt(index))) { // we have >, < or = on their own
+ return true;
+ } else if ((look == '<') && ((formulaStr.charAt(index) == '>') || formulaStr.charAt(index) == '=')) { // <>, or <=
+ return true;
+ } else if ((look == '>') && (formulaStr.charAt(index) == '=')) { // >=
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Identify <, >, <=, >=, =, <>
+ *
+ * @param The <code>String</code> which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isLogicalOp(String op) {
+ return ((op.compareTo(">") == 0) ||
+ (op.compareTo("<") == 0) ||
+ (op.compareTo(">=") == 0) ||
+ (op.compareTo("<=") == 0) ||
+ (op.compareTo("=") == 0) ||
+ (op.compareTo("<>") == 0));
+ }
+
+
+ /**
+ * Identify characters that MAY be logical operator characters
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isLogicalOpChar(char c) {
+ return (c == '>') || (c == '<') || (c == '=');
+ }
+
+ /**
+ * Identify special Cell Reference charaters
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isCellRefSpecialChar(char c) {
+ return (c == ':') || (c == '$') || (c == '.');
+ }
+
+ /**
+ * Identify letters
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isAlpha(char c) {
+ return(Character.isLetter(c));
+ }
+
+ /**
+ * Identify numbers
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isDigit(char c) {
+ return(Character.isDigit(c));
+ }
+
+ /**
+ * Identify numbers
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isPercent(char c) {
+ return (c == '%');
+ }
+
+ /**
+ * Identify letters or numbers
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isAlphaNum(char c) {
+ return(isAlpha(c) || isDigit(c));
+ }
+
+ /**
+ * Identify valid Characters for cell references
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isCellRefChar(char c) {
+ return(isAlpha(c) || isDigit(c) || isCellRefSpecialChar(c));
+ }
+
+ /**
+ * Test if current character is a match and move to next character
+ *
+ * @param c The character which is to be matched
+ */
+ private void match(char c) throws FormulaParsingException {
+
+ if(look==c) {
+ Debug.log(Debug.TRACE,"Operator Found : " + look);
+ getChar();
+ skipWhite();
+ }
+ else
+ throw new FormulaParsingException("Unexpected character '" + c + "'" + makeErrorString());
+ }
+
+ /**
+ * Test if current character is a match and move to next character
+ *
+ * @param symbol The <code>String</code> to be matched.
+ */
+ private void match(String symbol) throws FormulaParsingException {
+
+ int numChars = symbol.length();
+ boolean bContinue = true;
+ for (int i=0;i<numChars && bContinue; i++) {
+ if (look == symbol.charAt(i)) {
+ bContinue = getChar();
+ skipWhite();
+ } else {
+ throw new FormulaParsingException("Unexpected character '" + symbol + "'" + makeErrorString());
+ }
+ }
+ }
+
+ /**
+ * Skip over whitespaces (ie. spaces and tabs)
+ */
+ private void skipWhite() throws FormulaParsingException {
+
+ boolean success = true;
+
+ while(Character.isWhitespace(look) && success) {
+ success = getChar();
+ }
+ }
+
+ /**
+ * This is a factor for multiplication and division operators
+ */
+ private void factor() throws FormulaParsingException {
+ if(isAddOp(look)) { // handle unary addop
+ Character ch = new Character(look);
+ match(look);
+ tokenVector.add(tokenFactory.getOperatorToken(ch.toString(), 1));
+ }
+ if(look=='(') {
+ match('(');
+ tokenVector.add(tokenFactory.getOperatorToken("(", 1));
+ expression();
+ match(')');
+ tokenVector.add(tokenFactory.getOperatorToken(")", 1));
+ } else if(isDigit(look)){
+ getNum();
+ } else {
+ ident();
+ }
+ }
+
+ /**
+ * Pulls the next character from the <code>String</code>
+ *
+ * @return boolean false if the end if the statement
+ * is reached otherwise true
+ */
+ private boolean getChar() throws FormulaParsingException {
+
+ boolean success = true;
+
+ if(index<formulaStr.length()) {
+ look = formulaStr.charAt(index);
+ index++;
+ if(look==',')
+ success = false;
+ } else {
+ success = false;
+ }
+ return success;
+ }
+
+ /**
+ * Parses the number of arguments in a function
+ *
+ * @return The number of arguments
+ */
+ private int arguments() throws FormulaParsingException {
+ int numArgs;
+
+ skipWhite();
+ if(look==')')
+ numArgs = 0;
+ else
+ numArgs = 1;
+
+ while(look!=')') {
+ expression();
+ if(look==',') {
+ numArgs++;
+ match(',');
+ tokenVector.add(tokenFactory.getOperatorToken(",", 1));
+ }
+ }
+ return numArgs;
+ }
+
+ /**
+ * Test to see if we have come across a cell reference or a Name
+ * Definition.
+ */
+ private boolean isCellRef(String s) {
+ char c;
+ boolean result = false;
+
+ for(int i = 0;i<s.length();i++) {
+ c = s.charAt(i);
+ if(isCellRefSpecialChar(c)) {
+ result = true;
+ break;
+ }
+ }
+
+ // if it is a simple cell reference then there will not be a cell
+ // reference 'special char' so we should also look for a digit
+ if(!result) {
+ if(isDigit(s.charAt(1)) || isDigit(s.charAt(2))) {
+ result = true;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Test to see if we have come across a cell reference or a function and
+ * add the resulting toek nto the tokenVector.
+ */
+ private void ident() throws FormulaParsingException {
+
+ String cell = getTokenString();
+ if(look=='(') {
+ Debug.log(Debug.TRACE,"Found Function : " + cell);
+
+ int index = tokenVector.size();
+ match('(');
+ tokenVector.add(tokenFactory.getOperatorToken("(", 1));
+ int numArgs = arguments();
+ match(')');
+ tokenVector.add(tokenFactory.getOperatorToken(")", 1));
+ tokenVector.insertElementAt(tokenFactory.getFunctionToken(cell, numArgs), index);
+ } else {
+
+ if(cell.indexOf('.')!=-1) {
+ String cellRef = cell.substring(cell.indexOf('.') + 1, cell.length());
+ if(cellRef.indexOf(':')!=-1) {
+ tokenVector.add(tokenFactory.getOperandToken(cell, "3D_CELL_AREA_REFERENCE"));
+ } else {
+ tokenVector.add(tokenFactory.getOperandToken(cell, "3D_CELL_REFERENCE"));
+ }
+ } else if(cell.indexOf(':')!=-1) {
+ tokenVector.add(tokenFactory.getOperandToken(cell, "CELL_AREA_REFERENCE"));
+ } else if(isCellRef(cell)) {
+ tokenVector.add(tokenFactory.getOperandToken(cell, "CELL_REFERENCE"));
+ } else {
+ tokenVector.add(tokenFactory.getOperandToken(cell, "NAME"));
+ }
+ }
+ }
+
+ /**
+ * Will keep pulling valid logical operators from the formula and return
+ * the resultant <code>String</code>.
+ *
+ * @return a <code>String<code> representing a logical operator
+ */
+ private String getLogicalOperator() throws FormulaParsingException {
+ String op = new String();
+ boolean status;
+
+ do {
+ op += look;
+ status = getChar();
+ } while(isLogicalOpChar(look) && status);
+ skipWhite();
+ return op;
+ }
+
+ /**
+ * Keeps pulling characters from the statement until we get an
+ * operator and returns the resulting string.
+ *
+ * @return A <code>String</code>representing the next token
+ */
+ private String getTokenString() throws FormulaParsingException {
+
+ if(!isAlpha(look) && look!='$')
+ throw new FormulaParsingException("Expected Cell Reference" + makeErrorString());
+ else {
+ String cell = new String();
+ boolean status;
+ do {
+ cell += look;
+ status = getChar();
+ } while(isCellRefChar(look) && status);
+ skipWhite();
+ return cell;
+ }
+ }
+
+ /**
+ * Keeps pulling numbers from the statement and add the resulting integer
+ * token to the tokenVector.
+ */
+ private void getNum() throws FormulaParsingException {
+
+ Debug.log(Debug.TRACE,"getNum : ");
+ if(!isDigit(look))
+ throw new FormulaParsingException("Expected Integer" + makeErrorString());
+ else {
+ String num = new String();
+ boolean status;
+
+ do {
+ num += look;
+ status = getChar();
+ } while((isDigit(look) || ((look == '.') && isDigit(formulaStr.charAt(index)))) && status);
+ skipWhite();
+ tokenVector.add(tokenFactory.getOperandToken(num, "INTEGER"));
+ if(isPercent(look)) {
+ match(look);
+ tokenVector.add(tokenFactory.getOperatorToken("%", 1));
+ Debug.log(Debug.TRACE,"Added Percent token to Vector: ");
+ }
+ Debug.log(Debug.TRACE,"Number parsed : " + num);
+ }
+ }
+
+
+ /**
+ * Term will parse multiplication/division expressions
+ */
+ private void term() throws FormulaParsingException {
+ factor();
+ while(isMultiOp()) {
+ multiOp(Character.toString(look));
+ }
+ }
+
+ /**
+ * Expression is the entry point for the parser. It is the code
+ * that parses addition/subtraction expressions.
+ */
+ private void expression() throws FormulaParsingException {
+
+ if (look == '"') { //Extract a quoted string...
+ StringBuffer buff = new StringBuffer();
+ boolean success = true;
+ success = getChar();
+ while (look != '"' && success) {
+ buff.append(look);
+ success = getChar();
+ }
+
+ if (look != '"') { //We've reached the end of the string without getting a closing quote
+ throw new FormulaParsingException("Expected closing quote." + makeErrorString());
+ } else {
+ tokenVector.add(tokenFactory.getOperandToken(buff.toString(), "STRING"));
+ getChar(); //Move on to the next character
+ }
+ } else {
+ term();
+ }
+ while(isAddOp(look) || isLogicalOp()) {
+ if (isAddOp(look)) {
+ addOp(Character.toString(look));
+ } else if (isLogicalOp()) {
+ logicalOp();
+ }
+ }
+ }
+
+ /**
+ * Test to see if the next token (represented as a <code>String</code>) is
+ * the same as the String passed in. Move the index along to the end of
+ * that String and add that <code>Token</code> to the tokenVector. Then
+ * call <code>term</code> to parse the right hand side of the operator.
+ *
+ * @param op A <code>String</code> representing the operator
+ */
+ private void addOp(String op) throws FormulaParsingException {
+ match(op);
+ tokenVector.add(tokenFactory.getOperatorToken(op, 2));
+ term();
+ }
+
+ /**
+ * Test to see if the next token (represented as a <code>String</code>) is
+ * the same as the String passed in. Move the index along to the end of
+ * that String and add that <code>Token</code> to the tokenVector. Then
+ * call <code>factor</code> to parse the right hand side of the operator.
+ *
+ * @param op A <code>String</code> representing the operator
+ */
+ private void multiOp(String op) throws FormulaParsingException {
+ match(op);
+ tokenVector.add(tokenFactory.getOperatorToken(op, 2));
+ factor();
+ }
+
+ /**
+ * Pull a logical operator starting at the current index, add a token for
+ * that operator to the tokenVector and call <code>term<code> to parse the
+ * right hand side of the operator
+ */
+ private void logicalOp() throws FormulaParsingException {
+ String op = getLogicalOperator();
+ tokenVector.add(tokenFactory.getOperatorToken(op, 2));
+ term();
+ }
+
+ private String makeErrorString() {
+ StringBuffer buff = new StringBuffer();
+ for (int i=0; i<index-1; i++) {
+ buff.append(' ');
+ }
+
+ buff.append('^');
+ return "\n\t" + formulaStr + "\n\t" + buff.toString();
+ }
+ }
+
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaParsingException.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaParsingException.java
new file mode 100644
index 000000000000..e8465391e6ff
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FormulaParsingException.java
@@ -0,0 +1,41 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+/*
+ * If the formula failed to be parsed properly this exception will be thrown
+ *
+ * Martin Maher
+ */
+
+public class FormulaParsingException extends Exception {
+
+ public FormulaParsingException(String message) {
+ super(message);
+ }
+ }
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FunctionLookup.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FunctionLookup.java
new file mode 100644
index 000000000000..42c06d88754a
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/FunctionLookup.java
@@ -0,0 +1,204 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import java.util.HashMap;
+
+public class FunctionLookup extends SymbolLookup {
+
+ private HashMap stringToArgs = null;
+
+ /**
+ * The default constructor - invokes {@link #initialize() initialize()}
+ */
+ public FunctionLookup() {
+ initialize();
+ }
+
+ /**
+ * Initialize the lookup table for functions
+ */
+ public void initialize() {
+ if ((stringToID != null) || (idToString != null) || (stringToArgs !=null)) {
+ return;
+ }
+ stringToID = new HashMap();
+ idToString = new HashMap();
+ stringToArgs = new HashMap();
+
+ // Functions with Variable number of Arguments
+ // Math and Trig
+ addEntry("SUM", TokenConstants.TSUM, -1);
+ addEntry("MIN", TokenConstants.TMIN, -1);
+ addEntry("PRODUCT", TokenConstants.TPRODUCT, -1);
+ addEntry("LOG", TokenConstants.TLOG, -1);
+ addEntry("SUMIF", TokenConstants.TSUMIF, -1);
+ addEntry("TRUNC", TokenConstants.TRUNC, -1);
+ // Financial
+ addEntry("DDB", TokenConstants.TDDB, -1);
+ addEntry("FV", TokenConstants.TFV, -1);
+ addEntry("IRR", TokenConstants.TIRR, -1);
+ addEntry("NPER", TokenConstants.TNPER, -1);
+ addEntry("NPV", TokenConstants.TNPV, -1);
+ addEntry("PMT", TokenConstants.TPMT, -1);
+ addEntry("PV", TokenConstants.TPV, -1);
+ addEntry("RATE", TokenConstants.TRATE, -1);
+ // Statistical
+ addEntry("AVERAGE", TokenConstants.TAVERAGE, -1);
+ addEntry("COUNT", TokenConstants.TCOUNT, -1);
+ addEntry("COUNTA", TokenConstants.TCOUNTA, -1);
+ addEntry("MAX", TokenConstants.TMAX, -1 );
+ addEntry("MIN", TokenConstants.TMIN, -1);
+ addEntry("STDEV", TokenConstants.TSTDEV, -1 );
+ addEntry("STDEVP", TokenConstants.TSTDEVP, -1 );
+ addEntry("VAR", TokenConstants.TVAR, -1);
+ addEntry("VARP", TokenConstants.TVARP, -1);
+ // Lookup
+ addEntry("CHOOSE", TokenConstants.TCHOOSE, -1);
+ addEntry("HLOOKUP", TokenConstants.THLOOKUP, -1);
+ addEntry("INDEX", TokenConstants.TINDEX, -1);
+ addEntry("MATCH", TokenConstants.TMATCH, -1) ;
+ addEntry("VLOOKUP", TokenConstants.TVLOOKUP, -1);
+ // Text
+ addEntry("RIGHT", TokenConstants.TRIGHT, -1);
+ addEntry("SUBSTITUTE", TokenConstants.TSUBSTITUTE, -1);
+ addEntry("FIND", TokenConstants.TFIND, -1);
+ addEntry("LEFT", TokenConstants.TLEFT, -1);
+ // Logical
+ addEntry("AND", TokenConstants.TAND, -1 );
+ addEntry("IF", TokenConstants.TIF, -1) ;
+ addEntry("OR", TokenConstants.TOR, -1);
+
+ // Functions with Fixed number of Arguments
+ // Math and Trig
+ addEntry("ABS", TokenConstants.TABS, 1);
+ addEntry("ACOS", TokenConstants.TACOS, 1);
+ addEntry("ASIN", TokenConstants.TASIN, 1);
+ addEntry("ATAN", TokenConstants.TATAN, 1);
+ addEntry("ATAN2", TokenConstants.TATAN2, 1);
+ addEntry("COS", TokenConstants.TCOS, 1);
+ addEntry("COUNTIF", TokenConstants.TCOUNTIF, 1);
+ addEntry("DEGREES", TokenConstants.TDEGREES, 1);
+ addEntry("EXP", TokenConstants.TEXP, 1);
+ addEntry("FACT", TokenConstants.TFACT, 1);
+ addEntry("INT", TokenConstants.TINTE, 1);
+ addEntry("LN", TokenConstants.TLN, 1);
+ addEntry("LOG10", TokenConstants.TLOG10, 1);
+ addEntry("MOD", TokenConstants.TMOD, 1);
+ addEntry("PI", TokenConstants.TPI, 0);
+ addEntry("POWER", TokenConstants.TPOWERF, 2);
+ addEntry("RADIANS", TokenConstants.TRADIANS, 1);
+ addEntry("RAND", TokenConstants.TRAND, 1);
+ addEntry("ROUND", TokenConstants.TROUND, 1);
+ addEntry("SQRT", TokenConstants.TSQRT, 1);
+ addEntry("TAN", TokenConstants.TTAN, 1);
+ addEntry("SIN", TokenConstants.TSIN, 1);
+ // Financial
+ addEntry("SLN", TokenConstants.TSLN, 3);
+ addEntry("SYD", TokenConstants.TSYD, 4);
+ // Date and Time
+ addEntry("DATE", TokenConstants.TDATE, 3);
+ addEntry("DATEVALUE", TokenConstants.TDATEVALUE, 1);
+ addEntry("DAY", TokenConstants.TDAY, 1);
+ addEntry("HOUR", TokenConstants.THOUR, 1);
+ addEntry("MINUTE", TokenConstants.TMINUTE, 1 );
+ addEntry("MONTH", TokenConstants.TMONTH, 1);
+ addEntry("NOW", TokenConstants.TNOW, 0);
+ addEntry("SECOND", TokenConstants.TSECOND, 1);
+ addEntry("TIME", TokenConstants.TTIME, 3);
+ addEntry("TIMEVALUE", TokenConstants.TTIMEVALUE, 1);
+ addEntry("YEAR", TokenConstants.TYEAR, 1);
+ // Statistical
+ addEntry("COUNTBLANK", TokenConstants.TCOUNTBLANK, 1);
+ // lookup
+ addEntry("COLUMNS", TokenConstants.TCOLUMNS, 1);
+ addEntry("ROWS", TokenConstants.TROWS, 1);
+ // Database
+ addEntry("DAVERAGE", TokenConstants.TDAVAERAGE, 3);
+ addEntry("DCOUNT", TokenConstants.TDCOUNT, 3);
+ addEntry("DCOUNTA", TokenConstants.TDCOUNTA, 2);
+ addEntry("DGET", TokenConstants.TDGET, 3);
+ addEntry("DMAX", TokenConstants.TDMAX, 3);
+ addEntry("DMIN", TokenConstants.TDMIN, 3);
+ addEntry("DPRODUCT", TokenConstants.TDPRODUCT, 3);
+ addEntry("DSTDEV", TokenConstants.TDSTDEV, 3);
+ addEntry("DSTDEVP", TokenConstants.TDSTDEVP, 3) ;
+ addEntry("DSUM", TokenConstants.TDSUM, 3);
+ addEntry("DVAR", TokenConstants.TDVAR, 3);
+ addEntry("DVARP", TokenConstants.TDVARP, 3);
+ // Text
+ addEntry("EXACT", TokenConstants.TEXACT, 2);
+ addEntry("LEN", TokenConstants.TLEN, 1);
+ addEntry("LOWER", TokenConstants.TLOWER, 1);
+ addEntry("MID", TokenConstants.TMID, 3); // ??????
+ addEntry("PROPER", TokenConstants.TPROPER, 1);
+ addEntry("REPLACE", TokenConstants.TREPLACE, 4);
+ addEntry("REPT", TokenConstants.TREPT, 2);
+ addEntry("T", TokenConstants.TT, 1);
+ addEntry("TRIM", TokenConstants.TRIM, 1);
+ addEntry("UPPER", TokenConstants.TUPPER, 1);
+ addEntry("VALUE", TokenConstants.TVALUE, 1);
+ // Logical
+ addEntry("FALSE", TokenConstants.TFALSE, 0);
+ addEntry("NOT", TokenConstants.TNOT, 1);
+ addEntry("TRUE", TokenConstants.TTRUE, 0);
+ // Informational
+ addEntry("ERRORTYPE", TokenConstants.TERRORTYPE, 1);
+ addEntry("ISBLANK", TokenConstants.TISBLANK, 1);
+ addEntry("ISERR", TokenConstants.TISERR, 1);
+ addEntry("ISERROR", TokenConstants.TISERROR, 1);
+ addEntry("ISLOGICAL", TokenConstants.TISLOGICAL, 1);
+ addEntry("ISNA", TokenConstants.TISNA, 1);
+ addEntry("ISNONTEXT", TokenConstants.TISNONTEXT, 1);
+ addEntry("ISNUMBER", TokenConstants.TISNUMBER, 1);
+ addEntry("ISTEXT", TokenConstants.TISTEXT, 1);
+ addEntry("N", TokenConstants.TN, 1);
+ addEntry("NA", TokenConstants.TNA, 0);
+
+ }
+
+ /**
+ * Associate a function with an identifier and specifiy the number of arguments for that function
+ * @param symbol The function string that will act as the key in the lookup table
+ * @param id The identifier for the function
+ * @param args The number of arguments this function requires
+ */
+ public void addEntry(String symbol, int id, int args) {
+ addEntry(symbol, id);
+ stringToArgs.put(symbol, new Integer(args));
+ }
+
+ /**
+ * Retrieve the number of arguments for this function
+ * @param symbol The function name
+ * @return The number of arguments required by this function
+ */
+ public int getArgCountFromString(String symbol) {
+ return ((Integer)stringToArgs.get(symbol)).intValue();
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/OperandLookup.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/OperandLookup.java
new file mode 100644
index 000000000000..6ad1876e5358
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/OperandLookup.java
@@ -0,0 +1,62 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+import java.util.HashMap;
+
+/**
+ * A lookup table containing information about operands
+ */
+public class OperandLookup extends SymbolLookup {
+
+ /**
+ * The default constructor - invokes {@link #initialize() initialize()}
+ */
+ public OperandLookup() {
+ initialize();
+ }
+
+ /**
+ * Initialize the lookup table for operands
+ */
+ public void initialize() {
+ if ((stringToID != null) || (idToString != null)) {
+ return;
+ }
+ stringToID = new HashMap();
+ idToString = new HashMap();
+ addEntry("CELL_REFERENCE", TokenConstants.TREF);
+ addEntry("CELL_AREA_REFERENCE", TokenConstants.TAREA);
+ addEntry("INTEGER", TokenConstants.TNUM);
+ addEntry("NUMBER", TokenConstants.TNUM);
+ addEntry("STRING", TokenConstants.TSTRING);
+ addEntry("NAME", TokenConstants.TNAME);
+ addEntry("3D_CELL_REFERENCE", TokenConstants.TREF3D);
+ addEntry("3D_CELL_AREA_REFERENCE", TokenConstants.TAREA3D);
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/OperatorLookup.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/OperatorLookup.java
new file mode 100644
index 000000000000..de9ed23d8a24
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/OperatorLookup.java
@@ -0,0 +1,73 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import java.util.HashMap;
+
+/**
+ * A lookup table containing information about operators
+ */
+public class OperatorLookup extends SymbolLookup {
+
+ /**
+ * The default constructor - invokes {@link #initialize() initialize()}
+ */
+ public OperatorLookup() {
+ initialize();
+ }
+
+ /**
+ * Initialize the lookup table for operators
+ */
+ public void initialize() {
+ if ((stringToID != null) || (idToString != null)) {
+ return;
+ }
+ stringToID = new HashMap();
+ idToString = new HashMap();
+ addEntry("UNARY_PLUS", TokenConstants.TUPLUS);
+ addEntry("UNARY_MINUS", TokenConstants.TUMINUS);
+ addEntry("%", TokenConstants.TPERCENT);
+ addEntry("+", TokenConstants.TADD);
+ addEntry("-", TokenConstants.TSUB);
+ addEntry("*", TokenConstants.TMUL);
+ addEntry("/", TokenConstants.TDIV);
+ addEntry(",", TokenConstants.TARGSEP);
+ addEntry("^", TokenConstants.TPOWER);
+ addEntry("&", TokenConstants.TCONCAT);
+ addEntry("(", TokenConstants.TPAREN);
+ addEntry(")", TokenConstants.TCLOSEPAREN);
+ addEntry("<", TokenConstants.TLESS);
+ addEntry(">", TokenConstants.TGREATER);
+ addEntry(">=", TokenConstants.TGTEQUALS);
+ addEntry("<=", TokenConstants.TLESSEQUALS);
+ addEntry("=", TokenConstants.TEQUALS);
+ addEntry("<>", TokenConstants.TNEQUALS);
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/ParseToken.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/ParseToken.java
new file mode 100644
index 000000000000..053266c8008b
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/ParseToken.java
@@ -0,0 +1,42 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+public interface ParseToken
+{
+ public boolean isOperand();
+ public boolean isOperator();
+ public int getTokenType();
+
+ //GENERIC TOKENS (MOSTLY UNUSED
+ public static final int TOKEN_OPERATOR = 1;
+ public static final int TOKEN_OPERAND = 2;
+ public static final int TOKEN_FUNCTION_FIXED = 3;
+ public static final int TOKEN_FUNCTION_VARIABLE = 4;
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/PrecedenceTable.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/PrecedenceTable.java
new file mode 100644
index 000000000000..551b77cf6e7f
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/PrecedenceTable.java
@@ -0,0 +1,85 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import java.util.HashMap;
+
+/**
+ * This class defines the precedence applied to each operator when performing a conversion
+ * {@link org.openoffice.xmerge.converter.xml.sxc.pexcel.Records.formula.FormulaCompiler.infix2 from infix to RPN.}.
+ */
+public class PrecedenceTable {
+ public static final int DEFAULT_PRECEDENCE = 0;
+ public static final int EQNEQ_PRECEDENCE = 1; // =, <>
+ public static final int GTLTEQ_PRECEDENCE = 1; // >=, <=
+ public static final int GTLT_PRECEDENCE = 2; // >, <
+ public static final int ADDOP_PRECEDENCE = 4; // +, -
+ public static final int MULTOP_PRECEDENCE = 5; // *, /
+ public static final int FACTOR_PRECEDENCE = 6; // ^
+ public static final int CONCAT_PRECEDENCE = 6; // &
+ public static final int UNARY_PRECEDENCE = 7; // !, Unary +, Unary -
+ public static final int PAREN_PRECEDENCE = 8; // (, )
+ public static final int FUNCTION_PRECEDENCE = 8;
+ public static final int COMMA_PRECEDENCE = 8;
+
+ private static HashMap map;
+ static {
+ map = new HashMap();
+
+ map.put("%", new Integer(UNARY_PRECEDENCE));
+ map.put("+", new Integer(ADDOP_PRECEDENCE));
+ map.put("-", new Integer(ADDOP_PRECEDENCE));
+ map.put("*", new Integer(MULTOP_PRECEDENCE));
+ map.put("/", new Integer(MULTOP_PRECEDENCE));
+ map.put("(", new Integer(PAREN_PRECEDENCE));
+ map.put(")", new Integer(PAREN_PRECEDENCE));
+ map.put(",", new Integer(COMMA_PRECEDENCE));
+ map.put(">", new Integer(GTLT_PRECEDENCE));
+ map.put("<", new Integer(GTLT_PRECEDENCE));
+ map.put("=", new Integer(EQNEQ_PRECEDENCE));
+ map.put("&", new Integer(CONCAT_PRECEDENCE));
+ map.put("^", new Integer(FACTOR_PRECEDENCE));
+ map.put(">=", new Integer(GTLTEQ_PRECEDENCE));
+ map.put("<=", new Integer(GTLTEQ_PRECEDENCE));
+ map.put("<>", new Integer(EQNEQ_PRECEDENCE));
+ map.put("FUNCTION", new Integer(FUNCTION_PRECEDENCE));
+ }
+
+ /**
+ * Retrieve the precedence value for a given operator.
+ * @param op Look up the precedence for this operator
+ * @return an integer representing the integer value of the operator
+ */
+ public static int getPrecedence(String op) {
+ Object obj = map.get(op);
+ if (obj == null) {
+ return DEFAULT_PRECEDENCE;
+ }
+ return ((Integer)obj).intValue();
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/SymbolLookup.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/SymbolLookup.java
new file mode 100644
index 000000000000..bf7722b973e4
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/SymbolLookup.java
@@ -0,0 +1,81 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import java.util.HashMap;
+
+/**
+ * This interface defines the attributes of a lookup table for this plugin.
+ * Symbols will generally be either operators (_, -, *, etc) or funtion names.
+ */
+public abstract class SymbolLookup {
+
+ protected HashMap stringToID = null;
+ protected HashMap idToString = null;
+
+ /**
+ * Perform lookup table specific initialization. This would typically entail loading values into
+ * the lookup table. It is best to optimize this process so that data is loaded statically and shared
+ * across all instances of the lookup table.
+ */
+ abstract public void initialize();
+
+ /**
+ * Associate a symbol with a numeric value in the lookup table
+ * @param symbol The symbol that will act as the key in the lookup table
+ * @param value The value to be associated with a given symbol
+ */
+ public void addEntry(String symbol, int id) {
+ Integer iObj = new Integer(id);
+ stringToID.put(symbol, iObj);
+ idToString.put(iObj, symbol);
+ }
+
+ /**
+ * Retrieve the symbol associated with a given identifier
+ * @param id The identfier for which we need to retieve the symbol string
+ * @return The string associated with this identifier in the lookup table.
+ */
+ public String getStringFromID(int id) {
+ return (String)idToString.get(new Integer(id));
+ }
+
+ /**
+ * Retrieve the identifier associated with a given symbol
+ * @param symbol The symbol for which we need to retieve the identifier
+ * @throws UnsupportedFunctionException Thown when the symbol is not found in the lookup table
+ * @return The identifier associated with this string in the lookup table.
+ */
+ public int getIDFromString(String symbol) throws UnsupportedFunctionException {
+ Integer i = (Integer)stringToID.get(symbol);
+ if (i == null)
+ throw new UnsupportedFunctionException("Token '" + symbol + "' not supported by Pocket Excel");
+
+ return ((Integer)stringToID.get(symbol)).intValue();
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/Token.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/Token.java
new file mode 100644
index 000000000000..48d35dcef5d1
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/Token.java
@@ -0,0 +1,151 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+
+/**
+ * A Token is the basic building block of any formula.
+ * A Token can be of four types (Operator, Operand, Function with fixed
+ * arguments and function with a variable number of arguments. Each type can
+ * have numerous id's. Thetypes are define in <code>ParseToken</code> and the
+ * id's are defined in <code>TokenConstants</code>. The other member variables
+ * are priority which is returned from the <code>PrecedenceTable</code>, the
+ * value which is the String equivalent of the token (eg. "+", "$A$12", "SUM")
+ * and the number of arguments which is only valid for operators and functions.
+ * Tokens should never be created directly and instead are created by the
+ * <code>TokenFactory</code>
+ */
+public class Token implements ParseToken {
+
+ private String value;
+ private int type; // operator, operand, function fixed, function variable
+ private int id; // cell reference, SUM, integer
+ private int priority;
+ private int numArgs=-1;
+
+ public Token(String op, int type, int id, int args) {
+ this.value = op;
+ this.type = type;
+ this.id = id;
+ this.numArgs = args;
+ if(type==ParseToken.TOKEN_FUNCTION_VARIABLE) {
+ priority = PrecedenceTable.getPrecedence("FUNCTION");
+ } else if(type==ParseToken.TOKEN_OPERATOR) {
+ priority = PrecedenceTable.getPrecedence(op);
+ } else {
+ priority = PrecedenceTable.getPrecedence("DEFAULT");
+ }
+ }
+
+ /**
+ * Checks if the current token is an operator
+ *
+ * @return A <code>boolean</code> result of the comaparison
+ */
+ public boolean isOperator() {
+ return type == ParseToken.TOKEN_OPERATOR;
+ }
+
+ /**
+ * Checks if the current token is an operand
+ *
+ * @return A <code>boolean</code> result of the comaparison
+ */
+ public boolean isOperand() {
+ return type == ParseToken.TOKEN_OPERAND;
+ }
+
+ /**
+ * Checks if the current token is a function
+ *
+ * @return A <code>boolean</code> result of the comaparison
+ */
+ public boolean isFunction() {
+ return (type==ParseToken.TOKEN_FUNCTION_FIXED) || (type==ParseToken.TOKEN_FUNCTION_VARIABLE);
+ }
+
+ /**
+ * Returns the token type. This can be one of four values (TOKEN_OPERATOR,
+ * TOKEN_OPERAND, TOKEN_FUNCTION_FIXED, TOKEN_FUNCTION_VARIABLE) defined in
+ * <code>ParseToken</code>
+ *
+ * @return A <code>boolean</code> result of the comparison
+ */
+ public int getTokenType() {
+
+ return type;
+ }
+
+ /**
+ * Returns the ID of this token. This ID is equivalent to the pexcel hex
+ * value and is defined in <code>ParseToken</code>
+ *
+ * @return Returns the id of this token
+ */
+ public int getTokenID() {
+
+ return id;
+ }
+
+ /**
+ * Returns the <code>String</code> equivalent of this token
+ *
+ * @return The <code>String</code> representing this Token
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Returns the number of arguments if this token represents an operator or
+ * function. Otherwise returns -1.
+ *
+ * @return The number of arguments
+ */
+ public int getNumArgs() {
+ return numArgs;
+ }
+
+ /**
+ * Checks if the current token is an operator
+ *
+ * @return A <code>boolean</code> result of the comparison
+ */
+ public int getTokenPriority() {
+ return priority;
+ }
+
+ /**
+ * Returns the <code>String</code> equivalent of this token
+ *
+ * @return The <code>String</code> representing this Token
+ */
+ public String toString() {
+ return getValue();
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenConstants.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenConstants.java
new file mode 100644
index 000000000000..1a636f9ae1f1
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenConstants.java
@@ -0,0 +1,203 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+public interface TokenConstants {
+
+ // Unary Operator Tokens
+ public static final int TUPLUS = 0x12;
+ public static final int TUMINUS = 0x13;
+ public static final int TPERCENT = 0x14;
+ public static final int TPAREN = 0x15;
+ // Binary Operator Tokens
+ public static final int TADD = 0x03;
+ public static final int TSUB = 0x04;
+ public static final int TMUL = 0x05;
+ public static final int TDIV = 0x06;
+ public static final int TPOWER = 0x07;
+ public static final int TCONCAT = 0x08;
+
+ //Logical operators
+ public static final int TLESS = 0x09;
+ public static final int TLESSEQUALS = 0x0A;
+ public static final int TEQUALS = 0x0B;
+ public static final int TGTEQUALS = 0x0C;
+ public static final int TGREATER = 0x0D;
+ public static final int TNEQUALS = 0x0E;
+
+ // Function Operator Tokens
+ public static final int TFUNC = 0x41;
+ public static final int TFUNCVAR = 0x42;
+
+ // Constant Operand Tokens
+ public static final int TSTRING = 0x17;
+ public static final int TINT = 0x1E;
+ public static final int TNUM = 0x1F;
+ // Operand Tokens
+ public static final int TREF = 0x44;
+ public static final int TAREA = 0x25;
+ public static final int TNAME = 0x23;
+ public static final int TREF3D = 0x3A;
+ public static final int TAREA3D = 0x3B;
+
+ //
+ public static final int TARGSEP = 0x1001;
+ public static final int TCLOSEPAREN = 0x1002;
+
+ // Variable argument Functions
+ // Math and Trig
+ public static final int TSUM = 0x04;
+ public static final int TPRODUCT = 0xB7;
+ public static final int TSUMIF = 0x0159;
+ public static final int TLOG = 0x6D;
+ public static final int TRUNC = 0xC5;
+ // Financial
+ public static final int TDDB = 0x90;
+ public static final int TFV = 0x39;
+ public static final int TIRR = 0x3E;
+ public static final int TNPER = 0x3A;
+ public static final int TNPV = 0x0B;
+ public static final int TPMT = 0x3B;
+ public static final int TPV = 0x38;
+ public static final int TRATE = 0x3C;
+ // Statistical
+ public static final int TAVERAGE = 0x05;
+ public static final int TCOUNT = 0x00;
+ public static final int TCOUNTA = 0xA9;
+ public static final int TMAX = 0x07;
+ public static final int TMIN = 0x06;
+ public static final int TSTDEV = 0x0C;
+ public static final int TSTDEVP = 0xC1;
+ public static final int TVAR = 0x2E;
+ public static final int TVARP = 0xC2;
+ // Lookup
+ public static final int TCHOOSE = 0x64;
+ public static final int THLOOKUP = 0x65;
+ public static final int TINDEX = 0x1D;
+ public static final int TMATCH = 0x40;
+ public static final int TVLOOKUP = 0x66;
+ // Text
+ public static final int TRIGHT = 0x74;
+ public static final int TSUBSTITUTE = 0x78;
+ public static final int TFIND = 0x7c;
+ public static final int TLEFT = 0x73;
+ // Logical
+ public static final int TAND = 0x24; // 42
+ public static final int TIF = 0x01; // 42
+ public static final int TOR = 0x25; // 42
+
+ // Fixed argument Functions
+ // Math and Trig
+ public static final int TABS = 0x18;
+ public static final int TACOS = 0x63;
+ public static final int TASIN = 0x62;
+ public static final int TATAN = 0x12;
+ public static final int TATAN2 = 0x61;
+ public static final int TCOS = 0x10;
+ public static final int TSIN = 0x0F;
+
+ public static final int TCOUNTIF = 0x015A;
+ public static final int TDEGREES = 0x0157;
+ public static final int TEXP = 0x15;
+ public static final int TFACT = 0xB8;
+ public static final int TINTE = 0x19;
+ public static final int TLN = 0x16;
+
+ public static final int TLOG10 = 0x17;
+ public static final int TMOD = 0x27;
+ public static final int TPI = 0x13;
+
+ public static final int TPOWERF = 0x0151;
+ public static final int TRADIANS = 0x0156;
+ public static final int TRAND = 0x3F;
+ public static final int TROUND = 0x1B;
+ public static final int TSQRT = 0x14;
+ public static final int TTAN = 0x11;
+
+ public static final int TSLN = 0x8E;
+ public static final int TSYD = 0x8F;
+
+ // Date and Time
+ public static final int TDATE = 0x41;
+ public static final int TDATEVALUE = 0x8C;
+ public static final int TDAY = 0x43;
+ public static final int THOUR = 0x47;
+ public static final int TMINUTE = 0x48;
+ public static final int TMONTH = 0x44;
+ public static final int TNOW = 0x4A;
+ public static final int TSECOND = 0x49;
+ public static final int TTIME = 0x42;
+ public static final int TTIMEVALUE = 0x8D;
+ public static final int TYEAR = 0x45;
+ // Statistical
+ public static final int TCOUNTBLANK = 0x015B ;
+ // lookup
+ public static final int TCOLUMNS = 0x4D;
+ public static final int TROWS = 0x4C;
+ // Database
+ public static final int TDAVAERAGE = 0x2A;
+ public static final int TDCOUNT = 0x28;
+ public static final int TDCOUNTA = 0xC7;
+ public static final int TDGET = 0xEB;
+ public static final int TDMAX = 0x2C;
+ public static final int TDMIN = 0x2B;
+ public static final int TDPRODUCT = 0xBD;
+ public static final int TDSTDEV = 0x2D;
+ public static final int TDSTDEVP = 0xC3;
+ public static final int TDSUM = 0x29;
+ public static final int TDVAR = 0x2F;
+ public static final int TDVARP = 0xC4;
+ // Text
+ public static final int TEXACT = 0x75;
+ public static final int TLEN = 0x20;
+ public static final int TLOWER = 0x70;
+ public static final int TMID = 0x1F; // ??????
+ public static final int TPROPER = 0x72;
+ public static final int TREPLACE = 0x77;
+ public static final int TREPT = 0x1E;
+ public static final int TT = 0x82;
+ public static final int TRIM = 0x76;
+ public static final int TUPPER = 0x71;
+ public static final int TVALUE = 0x21;
+ // Logical
+ public static final int TFALSE = 0x23;
+ public static final int TNOT = 0x26;
+ public static final int TTRUE = 0x22;
+ // Informational
+ public static final int TERRORTYPE = 0x05;
+ public static final int TISBLANK = 0x81;
+ public static final int TISERR = 0x7E;
+ public static final int TISERROR = 0x03;
+ public static final int TISLOGICAL = 0xC6;
+ public static final int TISNA = 0x02;
+ public static final int TISNONTEXT = 0xBE;
+ public static final int TISNUMBER = 0x80;
+ public static final int TISTEXT = 0x7F;
+ public static final int TN = 0x83;
+ public static final int TNA = 0x0A;
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenDecoder.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenDecoder.java
new file mode 100644
index 000000000000..e18c1d10cc04
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenDecoder.java
@@ -0,0 +1,497 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import java.io.*;
+import java.util.Vector;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.DefinedName;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook;
+
+/**
+ * The TokenDecoder decodes a byte[] to an equivalent <code>String</code>. The only
+ * public method apart from the default constructor is the getTokenVector method.
+ * This method takes an entire formula as a pexcel byte[] and decodes it into
+ * a series of <code>Token</code>s. It adds these to a <code>Vector</code> which
+ * is returned once all the tokens have been decoded. The Decoder supports
+ * the following tokens.<br><br>
+ *
+ * Operands Floating point's, Cell references (absolute and relative),
+ * cell ranges<br>
+ * Operators +,-,*,/,&lt;,&gt;.&lt;=,&gt;=,&lt;&gt;<br>
+ * Functions All pexcel fixed and varaible argument functions
+ *
+ */
+public class TokenDecoder {
+
+ private TokenFactory tf;
+ private FunctionLookup fl;
+ private OperatorLookup operatorLookup;
+ private OperandLookup operandLookup;
+ private Workbook wb;
+
+ /**
+ * Default Constructor initializes the <code>TokenFactory</code> for generating
+ * <code>Token</code> and the <code>SymbolLookup</code> for generating
+ * Strings from hex values.
+ */
+ public TokenDecoder() {
+ tf = new TokenFactory();
+ fl = new FunctionLookup();
+ operatorLookup = new OperatorLookup();
+ operandLookup = new OperandLookup();
+ }
+
+ /**
+ * Sets global workbook data needed for defined names
+ */
+ public void setWorkbook(Workbook wb) {
+
+ Debug.log(Debug.TRACE, "TokenDecoder : setWorkbook");
+ this.wb = wb;
+ }
+
+ /**
+ * Returns a <code>Vector</code> of <code>Token</code> decoded from a
+ * byte[]. The byte[] is first converted to a
+ * <code>ByteArrayInputStream</code> as this is the easiest way of reading
+ * bytes.
+ *
+ * @param formula A Pocket Excel Formula byte[]
+ * @return A <code>Vector</code> of deoded <code>Token</code>
+ */
+ public Vector getTokenVector(byte[] formula) {
+
+ Vector v = new Vector();
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(formula);
+ int b = 0 ;
+ Token t;
+
+ while ((b = bis.read())!=-1)
+ {
+
+
+ switch (b) {
+
+ case TokenConstants.TAREA3D:
+ Debug.log(Debug.TRACE, "Decoded 3D Area Cell Reference: ");
+ v.add(read3DCellAreaRefToken(bis));
+ Debug.log(Debug.TRACE, "Decoded 3D Area Cell Reference: " + v.lastElement());
+ break;
+ case TokenConstants.TREF3D:
+ Debug.log(Debug.TRACE, "Decoded 3D Cell Reference: ");
+ v.add(read3DCellRefToken(bis));
+ Debug.log(Debug.TRACE, "Decoded 3D Cell Reference: " + v.lastElement());
+ break;
+ case TokenConstants.TREF :
+ v.add(readCellRefToken(bis));
+ Debug.log(Debug.TRACE, "Decoded Cell Reference: " + v.lastElement());
+ break;
+ case TokenConstants.TAREA :
+ v.add(readCellAreaRefToken(bis));
+ Debug.log(Debug.TRACE, "Decoded Cell Area Reference: " + v.lastElement());
+ break;
+ case TokenConstants.TNUM :
+ v.add(readNumToken(bis));
+ Debug.log(Debug.TRACE, "Decoded number : " + v.lastElement());
+ break;
+ case TokenConstants.TFUNCVAR :
+ v.add(readFunctionVarToken(bis));
+ Debug.log(Debug.TRACE, "Decoded variable argument function: " + v.lastElement());
+ break;
+ case TokenConstants.TFUNC :
+ v.add(readFunctionToken(bis));
+ Debug.log(Debug.TRACE, "Decoded function: " + v.lastElement());
+ break;
+ case TokenConstants.TSTRING :
+ v.add(readStringToken(bis));
+ Debug.log(Debug.TRACE, "Decoded string: " + v.lastElement());
+ break;
+ case TokenConstants.TNAME :
+ v.add(readNameToken(bis));
+ Debug.log(Debug.TRACE, "Decoded defined name: " + v.lastElement());
+ break;
+ case TokenConstants.TUPLUS:
+ case TokenConstants.TUMINUS:
+ case TokenConstants.TPERCENT:
+ v.add(readOperatorToken(b, 1));
+ Debug.log(Debug.TRACE, "Decoded Unary operator : " + v.lastElement());
+ break;
+ case TokenConstants.TADD :
+ case TokenConstants.TSUB :
+ case TokenConstants.TMUL :
+ case TokenConstants.TDIV :
+ case TokenConstants.TLESS :
+ case TokenConstants.TLESSEQUALS :
+ case TokenConstants.TEQUALS :
+ case TokenConstants.TGTEQUALS :
+ case TokenConstants.TGREATER :
+ case TokenConstants.TNEQUALS :
+ v.add(readOperatorToken(b, 2));
+ Debug.log(Debug.TRACE, "Decoded Binary operator : " + v.lastElement());
+ break;
+
+ default :
+ Debug.log(Debug.TRACE, "Unrecognized byte : " + b);
+ }
+ }
+ return v;
+ }
+
+ /**
+ * Converts a zero based integer to a char (eg. a=0, b=1).
+ * It assumes the integer is less than 26.
+ *
+ * @param i A 0 based index
+ * @return The equivalent character
+ */
+ private char int2Char(int i) {
+ return (char) ('A' + i);
+ }
+
+ /**
+ * Reads a Cell Reference token from the <code>ByteArrayInputStream</code>
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The decoded String <code>Token</code>
+ */
+ private Token readStringToken(ByteArrayInputStream bis) {
+
+ int len = ((int)bis.read())*2;
+ int options = (int)bis.read();
+ Debug.log(Debug.TRACE,"String length is " + len + " and Options Flag is " + options);
+ byte [] stringBytes = new byte[len];
+ int numRead =0;
+ if ((numRead = bis.read(stringBytes, 0, len)) != len) {
+ Debug.log(Debug.TRACE,"Expected " + len + " bytes. Could only read " + numRead + " bytes.");
+ //throw new IOException("Expected " + len + " bytes. Could only read " + numRead + " bytes.");
+ }
+ StringBuffer outputString = new StringBuffer();
+ outputString.append('"');
+ try {
+ Debug.log(Debug.TRACE,"Using LE encoding");
+ outputString.append(new String(stringBytes, "UTF-16LE"));
+ } catch (IOException eIO) {
+ outputString.append(new String(stringBytes)); //fall back to default encoding
+ }
+ outputString.append('"');
+
+ return (tf.getOperandToken(outputString.toString(), "STRING"));
+ }
+
+ /**
+ * Reads a Defined Name token from the <code>ByteArrayInputStream</code>
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The decoded Name <code>Token</code>
+ */
+ private Token readNameToken(ByteArrayInputStream bis) {
+ byte buffer[] = new byte[2];
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int nameIndex = EndianConverter.readShort(buffer);
+ bis.skip(12); // the next 12 bytes are unused
+ Enumeration e = wb.getDefinedNames();
+ int i = 1;
+ while(i<nameIndex) {
+ e.nextElement();
+ i++;
+ }
+ Debug.log(Debug.TRACE,"Name index is " + nameIndex);
+ DefinedName dn = (DefinedName)e.nextElement();
+ Debug.log(Debug.TRACE,"DefinedName is " + dn.getName());
+ return (tf.getOperandToken(dn.getName(), "NAME"));
+ }
+
+ /**
+ * Reads a Cell Reference token from the <code>ByteArrayInputStream</code>
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The decoded Cell Reference <code>Token</code>
+ */
+ private Token readCellRefToken(ByteArrayInputStream bis) {
+
+ byte buffer[] = new byte[2];
+ String outputString = new String();
+
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int formulaRow = EndianConverter.readShort(buffer);
+ int relativeFlags = (formulaRow & 0xC000)>>14;
+ formulaRow &= 0x3FFF;
+ int formulaCol = (byte) bis.read();
+
+ outputString = int2CellStr(formulaRow, formulaCol, relativeFlags);
+
+ return (tf.getOperandToken(outputString,"CELL_REFERENCE"));
+ }
+
+ /**
+ * Reads a Cell Reference token from the <code>ByteArrayInputStream</code>
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The decoded Cell Reference <code>Token</code>
+ */
+ private Token read3DCellRefToken(ByteArrayInputStream bis) {
+
+ byte buffer[] = new byte[2];
+ String outputString = new String();
+
+ bis.skip(10);
+
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int Sheet1 = EndianConverter.readShort(buffer);
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int Sheet2 = EndianConverter.readShort(buffer);
+
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int formulaRow = EndianConverter.readShort(buffer);
+ int relativeFlags = (formulaRow & 0xC000)>>14;
+ formulaRow &= 0x3FFF;
+ int formulaCol = (byte) bis.read();
+ String cellRef = "." + int2CellStr(formulaRow, formulaCol, relativeFlags);
+ if(Sheet1 == Sheet2) {
+ outputString = "$" + wb.getSheetName(Sheet1) + cellRef;
+ } else {
+ outputString = "$" + wb.getSheetName(Sheet1) + cellRef + ":$" + wb.getSheetName(Sheet2) + cellRef;
+ }
+
+ return (tf.getOperandToken(outputString,"3D_CELL_REFERENCE"));
+ }
+
+ /**
+ * Reads a Cell Reference token from the <code>ByteArrayInputStream</code>
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The decoded Cell Reference <code>Token</code>
+ */
+ private Token read3DCellAreaRefToken(ByteArrayInputStream bis) {
+
+ byte buffer[] = new byte[2];
+ String outputString = new String();
+
+ bis.skip(10);
+
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int Sheet1 = EndianConverter.readShort(buffer);
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int Sheet2 = EndianConverter.readShort(buffer);
+
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int formulaRow1 = EndianConverter.readShort(buffer);
+ int relativeFlags1 = (formulaRow1 & 0xC000)>>14;
+ formulaRow1 &= 0x3FFF;
+
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int formulaRow2 = EndianConverter.readShort(buffer);
+ int relativeFlags2 = (formulaRow2 & 0xC000)>>14;
+ formulaRow2 &= 0x3FFF;
+
+ int formulaCol1 = (byte) bis.read();
+ int formulaCol2 = (byte) bis.read();
+
+ String cellRef1 = "." + int2CellStr(formulaRow1, formulaCol1, relativeFlags1);
+ String cellRef2 = int2CellStr(formulaRow2, formulaCol2, relativeFlags2);
+
+ if(Sheet1 == Sheet2) {
+ outputString = "$" + wb.getSheetName(Sheet1) + cellRef1 + ":" + cellRef2;
+ } else {
+ outputString = "$" + wb.getSheetName(Sheet1) + cellRef1 + ":$" + wb.getSheetName(Sheet2) + "." + cellRef2;
+ }
+
+ return (tf.getOperandToken(outputString,"3D_CELL_AREA_REFERENCE"));
+ }
+
+ /**
+ * Converts a row and col 0 based index to a spreadsheet cell reference.
+ * It also has a relativeFlags which indicates whether or not the
+ * Cell Reference is relative or absolute (Absolute is denoted with '$')
+ *
+ * 00 = absolute row, absolute col
+ * 01 = absolute row, relative col
+ * 10 = relative row, absolute col
+ * 11 = relative row, relative col
+ *
+ * @param row The cell reference 0 based index to the row
+ * @param col The cell reference 0 based index to the row
+ * @param relativeFlags Flags indicating addressing of row and column
+ * @return A <code>String</code> representing a cell reference
+ */
+ private String int2CellStr(int row, int col, int relativeFlags) {
+ String outputString = "";
+ int firstChar = (col + 1) / 26;
+
+ if((relativeFlags & 1) == 0) {
+ outputString += "$";
+ }
+
+ if(firstChar>0) {
+ int secondChar = (col + 1) % 26;
+ outputString += Character.toString(int2Char(firstChar - 1)) + Character.toString(int2Char(secondChar - 1));
+ } else {
+ outputString += Character.toString(int2Char(col));
+ }
+ if((relativeFlags & 2) == 0) {
+ outputString += "$";
+ }
+ outputString += Integer.toString(row+1);
+ return outputString;
+ }
+
+ /**
+ * Reads a Cell Area Reference (cell range) <code>Token</code> from
+ * the <code>ByteArrayInputStream</code>
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The equivalent Cell Area Reference (cell range)
+ * <code>Token</code>
+ */
+ private Token readCellAreaRefToken(ByteArrayInputStream bis) {
+ byte buffer[] = new byte[2];
+ int formulaRow1, formulaRow2;
+ int formulaCol1, formulaCol2;
+
+ String outputString = new String();
+
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ formulaRow1 = EndianConverter.readShort(buffer);
+ int relativeFlags1 = (formulaRow1 & 0xC000)>>14;
+ formulaRow1 &= 0x3FFF;
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ formulaRow2 = EndianConverter.readShort(buffer);
+ int relativeFlags2 = (formulaRow2 & 0xC000)>>14;
+ formulaRow2 &= 0x3FFF;
+
+ formulaCol1 = (byte) bis.read();
+ formulaCol2 = (byte) bis.read();
+
+ outputString = int2CellStr(formulaRow1, formulaCol1, relativeFlags1);
+ outputString += (":" + int2CellStr(formulaRow2, formulaCol2, relativeFlags2));
+
+ return (tf.getOperandToken(outputString,"CELL_AREA_REFERENCE"));
+ }
+
+
+ /**
+ * Reads a Number (floating point) token from the <code>ByteArrayInputStream</code>
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The decoded Integer <code>Token</code>
+ */
+ private Token readNumToken(ByteArrayInputStream bis) {
+
+ byte numBuffer[] = new byte[8];
+
+ for(int j=0;j<8;j++) {
+ numBuffer[j]=(byte) bis.read();
+ }
+
+ return (tf.getOperandToken(Double.toString(EndianConverter.readDouble(numBuffer)),"NUMBER"));
+ }
+
+ /**
+ * Read an Operator token from the <code>ByteArrayInputStream</code>
+ *
+ * @param b A Pocket Excel number representing an operator.
+ * @param args The number of arguments this operator takes.
+ * @return The decoded Operator <code>Token</code>
+ */
+ private Token readOperatorToken(int b, int args) {
+
+ Token t;
+
+ if(b==TokenConstants.TUPLUS) {
+ t = tf.getOperatorToken("+", args);
+ } else if(b==TokenConstants.TUMINUS) {
+ t = tf.getOperatorToken("-", args);
+ } else {
+ t = tf.getOperatorToken(operatorLookup.getStringFromID(b), args);
+ }
+ return t;
+ }
+
+ /**
+ * Read a Function token from the <code>ByteArrayInputStream</code>
+ * This function can have any number of arguments and this number is read
+ * in with the record
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The decoded variable argument Function <code>Token</code>
+ */
+ private Token readFunctionVarToken(ByteArrayInputStream bis) {
+
+ int numArgs = 0;
+ numArgs = bis.read();
+ byte buffer[] = new byte[2];
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int functionID = EndianConverter.readShort(buffer);
+ return (tf.getFunctionToken(fl.getStringFromID(functionID),numArgs));
+ }
+
+ /**
+ * Read a Function token from the <code>ByteArrayInputStream</code>
+ * This function has a fixed number of arguments which it will get
+ * from <code>FunctionLookup</code>.
+ *
+ * @param bis The <code>ByteArrayInputStream</code> from which we read the
+ * bytes.
+ * @return The decoded fixed argument Function <code>Token</code>
+ */
+ private Token readFunctionToken(ByteArrayInputStream bis) {
+
+ byte buffer[] = new byte[2];
+ buffer[0] = (byte) bis.read();
+ buffer[1] = (byte) bis.read();
+ int functionID = EndianConverter.readShort(buffer);
+ String functionName = fl.getStringFromID(functionID);
+ return (tf.getFunctionToken(functionName,fl.getArgCountFromString(functionName)));
+ }
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenEncoder.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenEncoder.java
new file mode 100644
index 000000000000..249e14ac620f
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenEncoder.java
@@ -0,0 +1,559 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import java.io.*;
+import java.util.Vector;
+import java.util.Enumeration;
+
+import org.openoffice.xmerge.util.Debug;
+import org.openoffice.xmerge.util.EndianConverter;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.Workbook;
+import org.openoffice.xmerge.converter.xml.sxc.pexcel.records.DefinedName;
+
+/**
+ * The TokenEncoder encodes a Token to an equivalent pexcel byte[]. The only
+ * public method apart from the default constructor is the getByte method.
+ * This method picks an encoder based onthe Token's type or id field and uses
+ * that encoder to return a byte[] which it returns. This Encoder supports
+ * Operands Floating point's, Cell references (absolute and relative),
+ * cell ranges
+ * Operators +,-,*,/,&lt;,&gt;.&lt;=,&gt;=,&lt;&gt;
+ * Functions All pexcel fixed and varaible argument functions
+ *
+ */
+public class TokenEncoder {
+
+ private FunctionLookup fl;
+ private String parseString;
+ private int index;
+ private Workbook wb;
+
+ /**
+ * Default Constructor
+ */
+ public TokenEncoder() {
+
+ parseString = new String();
+ fl = new FunctionLookup();
+ }
+
+ /**
+ * Sets global workbook data needed for defined names
+ */
+ public void setWorkbook(Workbook wb) {
+
+ this.wb = wb;
+ }
+
+
+ /**
+ * Return the byte[] equivalent of a <code>Token</code>. The various
+ * encoders return <code>Vector</code> of <code>Byte</code> instead
+ * of byte[] because the number of bytes returned varies with each
+ * <code>Token</code> encoded. After the encoding is finished the Vector
+ * in converted to a byte[].
+ *
+ * @param t The <code>Token</code> to be encoded
+ * @return An equivalent Pocket Excel byte[]
+ */
+ public byte[] getByte(Token t) throws IOException {
+
+ Vector tmpByteArray = null; // we use this cause we don't know till after
+ // the encoding takes place how big the byte [] will be
+ //index=0; // This class is declared static in
+ // FormulaHelper so better make sure our index is 0
+ if(t.getTokenType()==ParseToken.TOKEN_OPERATOR) {
+ tmpByteArray = operatorEncoder(t);
+ } else if (t.getTokenType()==ParseToken.TOKEN_FUNCTION_VARIABLE || t.getTokenType()==ParseToken.TOKEN_FUNCTION_FIXED){
+ tmpByteArray = functionEncoder(t);
+ } else { // Operands and functions
+ switch(t.getTokenID()) {
+ case TokenConstants.TNAME :
+ tmpByteArray = nameDefinitionEncoder(t);
+ break;
+ case TokenConstants.TREF3D :
+ tmpByteArray = threeDCellRefEncoder(t);
+ break;
+ case TokenConstants.TAREA3D:
+ tmpByteArray = threeDAreaRefEncoder(t);
+ break;
+ case TokenConstants.TREF :
+ tmpByteArray = cellRefEncoder(t);
+ break;
+ case TokenConstants.TAREA :
+ tmpByteArray = areaRefEncoder(t);
+ break;
+ case TokenConstants.TNUM :
+ tmpByteArray = numEncoder(t);
+ break;
+ case TokenConstants.TSTRING :
+ tmpByteArray = stringEncoder(t);
+ break;
+ default :
+ Debug.log(Debug.ERROR, "Encoder found unrecognized Token");
+ }
+ }
+
+ byte cellRefArray[] = new byte[tmpByteArray.size()];
+ int i = 0;
+ String s = new String();
+ for(Enumeration e = tmpByteArray.elements();e.hasMoreElements();) {
+ Byte tmpByte = (Byte) e.nextElement();
+ s = s + tmpByte + " ";
+ cellRefArray[i] = tmpByte.byteValue();
+ i++;
+ }
+ Debug.log(Debug.TRACE, "Encoding Token " + t.getValue() + " as [" + s + "]");
+ return cellRefArray;
+ }
+
+ /**
+ * An Operator Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector operatorEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ return tmpByteArray;
+ }
+
+
+ /**
+ * A String Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector stringEncoder(Token t) throws IOException{
+
+ Vector tmpByteArray = new Vector();
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ tmpByteArray.add(new Byte((byte)(t.getValue().length())));
+ tmpByteArray.add(new Byte((byte)0x01));
+ byte [] stringBytes = t.getValue().getBytes("UTF-16LE");
+ for (int i=0; i<stringBytes.length; i++) {
+ tmpByteArray.add(new Byte(stringBytes[i]));
+ }
+ return tmpByteArray;
+ }
+
+
+ /**
+ * An Integer Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector numEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+
+ double cellLong = (double) Double.parseDouble(t.getValue());
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ byte[] tempByte = EndianConverter.writeDouble(cellLong);
+ for(int byteIter=0;byteIter<tempByte.length;byteIter++) {
+ tmpByteArray.add(new Byte(tempByte[byteIter]));
+ }
+ return tmpByteArray;
+ }
+
+ /**
+ * Converts a char to an int. It is zero based
+ * so a=0, b=1 etc.
+ *
+ * @param ch the character to be converted
+ * @return -1 if not a character otherwise a 0 based index
+ */
+ private int char2int(char ch) {
+ if(!Character.isLetter(ch))
+ return -1;
+
+ ch = Character.toUpperCase(ch);
+ return ch-'A';
+ }
+
+ /**
+ * Identify letters
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isAlpha(char c) {
+ return(Character.isLetter(c));
+ }
+
+ /**
+ * Identify numbers
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isDigit(char c) {
+ return(Character.isDigit(c));
+ }
+
+ /**
+ * Identify letters or numbers
+ *
+ * @param c The character which is to be identified
+ * @return A boolean returning the result of the comparison
+ */
+ private boolean isAlphaNum(char c) {
+ return(isAlpha(c) || isDigit(c));
+ }
+
+ /**
+ * Parses a column reference and returns it's integer equivalent. (eg.
+ * A=0, D=3, BA=27)
+ *
+ * @return an 0 based index to a column
+ */
+ private int column() {
+ char ch = parseString.charAt(index);
+ String columnStr = new String();
+ int col = 0;
+
+ while(isAlpha(ch)) {
+ columnStr += ch;
+ index++;
+ ch = parseString.charAt(index);
+ }
+
+ if(columnStr.length()==1) {
+ col = char2int(columnStr.charAt(0));
+ } else if (columnStr.length()==2) {
+ col = char2int(columnStr.charAt(0)) + 1;
+ col = (col*26) + char2int(columnStr.charAt(1));
+ } else {
+ Debug.log(Debug.ERROR, "Invalid Column Reference " + columnStr );
+ }
+
+
+ return col;
+ }
+
+ /**
+ * Parses a column reference and returns it's integer equivalent. (eg.
+ * A=0, D=3, BA=27)
+ *
+ * @return an 0 based index to a column
+ */
+ private int row() {
+ char ch = parseString.charAt(index);
+ String rowStr = new String();
+ int row = 0;
+ boolean status = true;
+
+ do {
+ rowStr += ch;
+ index++;
+ if(index>=parseString.length()) {
+ status = false;
+ } else {
+ ch = parseString.charAt(index);
+ }
+ } while(isDigit(ch) && status);
+ return Integer.parseInt(rowStr)-1; // Pexcel uses a 0 based index
+ }
+
+ /**
+ * A Cell Reference Encoder (It supports absolute and relative addressing)
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private byte[] encodeCellCoordinates(String cellCoordinates) {
+ int col = 0, row = 0;
+ int addressing = 0xC000;
+
+ index = 0;
+ parseString = cellCoordinates;
+ Debug.log(Debug.TRACE,"Encoding cell coordinates " + cellCoordinates);
+ if(cellCoordinates.charAt(index)=='$') {
+ addressing &= 0x8000;
+ index++;
+ }
+ col = column();
+ if(cellCoordinates.charAt(index)=='$') {
+ addressing &= 0x4000;
+ index++;
+ }
+ row = row(); // Pexcel uses a 0 based index
+ row |= addressing;
+ byte tokenBytes[] = new byte[3];
+ tokenBytes[0] = (byte)row;
+ tokenBytes[1] = (byte)(row>>8);
+ tokenBytes[2] = (byte)col;
+ return tokenBytes;
+ }
+
+ /**
+ * A name definition Encoder
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector nameDefinitionEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+
+ String nameString = t.getValue();
+ Debug.log(Debug.TRACE,"NameDefinitionEncoder : " + nameString);
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ Enumeration e = wb.getDefinedNames();
+ DefinedName dn;
+ String name;
+ int definedNameIndex = 0;
+ do {
+ dn = (DefinedName)e.nextElement();
+ name = dn.getName();
+ Debug.log(Debug.TRACE,"Name pulled from DefinedName : " + name);
+ definedNameIndex++;
+ } while(!nameString.equalsIgnoreCase(name) && e.hasMoreElements());
+
+ tmpByteArray.add(new Byte((byte)definedNameIndex));
+ tmpByteArray.add(new Byte((byte)0x00));
+
+ for(int i = 0;i < 12;i++) {
+ tmpByteArray.add(new Byte((byte)0x00));
+ }
+
+ return tmpByteArray;
+ }
+ /**
+ * A Cell Reference Encoder. It supports absolute and relative addressing
+ * but not sheetnames.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector cellRefEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ byte cellRefBytes[] = encodeCellCoordinates(t.getValue());
+ for(int i = 0;i < cellRefBytes.length;i++) {
+ tmpByteArray.add(new Byte(cellRefBytes[i]));
+ }
+ return tmpByteArray;
+ }
+
+ /**
+ * This function will find the sheetname index for a given String
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private short findSheetIndex(String s) {
+
+ short sheetIndex = 0;
+ String savedName;
+ String sheetName;
+ if (s.startsWith("$")) {
+ sheetName = s.substring(1,s.length()); // Remove $
+ } else {
+ sheetName = s.substring(0,s.length());
+ }
+ Debug.log(Debug.TRACE,"Searching for Worksheet : " + sheetName);
+ Vector names = wb.getWorksheetNames();
+ Enumeration e = names.elements();
+ do {
+ savedName = (String) e.nextElement();
+ sheetIndex++;
+ } while(!savedName.equalsIgnoreCase(sheetName) && e.hasMoreElements());
+
+ Debug.log(Debug.TRACE,"Setting sheetindex to " + sheetIndex);
+ return (short)(sheetIndex-1);
+ }
+
+ /**
+ * A 3D Cell reference encoder
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector threeDCellRefEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+ parseString = t.getValue();
+ Debug.log(Debug.TRACE,"Encoding 3D Cell reference " + t);
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ tmpByteArray.add(new Byte((byte)0xFF));
+ tmpByteArray.add(new Byte((byte)0xFF));
+ for(int i = 0;i < 8;i++) {
+ tmpByteArray.add(new Byte((byte)0x00));
+ }
+
+ String sheetRef = parseString.substring(0, parseString.indexOf('.') + 1);
+ if (sheetRef.indexOf(':')!=-1) {
+ sheetRef = parseString.substring(0, parseString.indexOf(':'));
+ short sheetNum1 = findSheetIndex(sheetRef);
+ sheetRef = parseString.substring(parseString.indexOf(':') + 1, parseString.length());
+ short sheetNum2 = findSheetIndex(sheetRef);
+ tmpByteArray.add(new Byte((byte)sheetNum1));
+ tmpByteArray.add(new Byte((byte)0x00));
+ tmpByteArray.add(new Byte((byte)sheetNum2));
+ tmpByteArray.add(new Byte((byte)0x00));
+ } else {
+ sheetRef = parseString.substring(0, parseString.indexOf('.'));
+ short sheetNum = findSheetIndex(sheetRef);
+ tmpByteArray.add(new Byte((byte)sheetNum));
+ tmpByteArray.add(new Byte((byte)0x00));
+ tmpByteArray.add(new Byte((byte)sheetNum));
+ tmpByteArray.add(new Byte((byte)0x00));
+ }
+ String s = parseString.substring(parseString.indexOf('.') + 1, parseString.length());
+ Debug.log(Debug.TRACE,"Parsing : " + s);
+ byte cellRefBytes[] = encodeCellCoordinates(s);
+ for(int i = 0;i < cellRefBytes.length;i++) {
+ tmpByteArray.add(new Byte(cellRefBytes[i]));
+ }
+ return tmpByteArray;
+ }
+ /**
+ * A 3D Area Reference Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector threeDAreaRefEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+ parseString = t.getValue();
+ Debug.log(Debug.TRACE,"Encoding 3D Area reference " + t);
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ tmpByteArray.add(new Byte((byte)0xFF));
+ tmpByteArray.add(new Byte((byte)0xFF));
+ for(int i = 0;i < 8;i++) {
+ tmpByteArray.add(new Byte((byte)0x00));
+ }
+
+ String param1= parseString.substring(0, parseString.indexOf(':'));
+ String cellRef1 = param1.substring(parseString.indexOf('.') + 1, param1.length());
+ String sheetRef1 = param1.substring(0, param1.indexOf('.'));
+ short sheetNum1 = findSheetIndex(sheetRef1);
+
+ String param2 = parseString.substring(parseString.indexOf(':') + 1, parseString.length());
+ Debug.log(Debug.TRACE,"param2: " + param2);
+ String cellRef2 = param2.substring(param2.indexOf('.') + 1, param2.length());
+ Debug.log(Debug.TRACE,"cellRef2: " + cellRef2);
+
+ if(param2.indexOf('.')==-1) {
+ tmpByteArray.add(new Byte((byte)sheetNum1));
+ tmpByteArray.add(new Byte((byte)0x00));
+ tmpByteArray.add(new Byte((byte)sheetNum1));
+ tmpByteArray.add(new Byte((byte)0x00));
+ } else {
+ String sheetRef2 = param2.substring(0, param2.indexOf('.'));
+ short sheetNum2 = findSheetIndex(sheetRef2);
+ tmpByteArray.add(new Byte((byte)sheetNum1));
+ tmpByteArray.add(new Byte((byte)0x00));
+ tmpByteArray.add(new Byte((byte)sheetNum2));
+ tmpByteArray.add(new Byte((byte)0x00));
+ }
+
+ byte cellRefBytes1[] = encodeCellCoordinates(cellRef1);
+ byte cellRefBytes2[] = encodeCellCoordinates(cellRef2);
+
+ tmpByteArray.add(new Byte(cellRefBytes1[0]));
+ tmpByteArray.add(new Byte(cellRefBytes1[1]));
+
+ tmpByteArray.add(new Byte(cellRefBytes2[0]));
+ tmpByteArray.add(new Byte(cellRefBytes2[1]));
+
+ tmpByteArray.add(new Byte(cellRefBytes1[2]));
+ tmpByteArray.add(new Byte(cellRefBytes2[2]));
+
+ return tmpByteArray;
+ }
+
+ /**
+ * A Cell Range Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector areaRefEncoder(Token t) {
+
+ Vector tmpByteArray = new Vector();
+
+ tmpByteArray.add(new Byte((byte)t.getTokenID()));
+ String param = t.getValue();
+ String cellRef1 = new String();
+ String cellRef2 = new String();
+
+ if(param.indexOf(':')==-1) {
+ Debug.log(Debug.ERROR, "Invalid Cell Range, could not find :");
+ } else {
+ cellRef1 = param.substring(0, param.indexOf(':'));
+ cellRef2 = param.substring(param.indexOf(':') + 1, param.length());
+ }
+ byte cellRefBytes1[] = encodeCellCoordinates(cellRef1);
+ byte cellRefBytes2[] = encodeCellCoordinates(cellRef2);
+
+ tmpByteArray.add(new Byte(cellRefBytes1[0]));
+ tmpByteArray.add(new Byte(cellRefBytes1[1]));
+
+ tmpByteArray.add(new Byte(cellRefBytes2[0]));
+ tmpByteArray.add(new Byte(cellRefBytes2[1]));
+
+ tmpByteArray.add(new Byte(cellRefBytes1[2]));
+ tmpByteArray.add(new Byte(cellRefBytes2[2]));
+
+ return tmpByteArray;
+ }
+
+ /**
+ * A Function Encoder.
+ *
+ * @param t <code>Token</code> to be encoded
+ * @return A <code>Vector</code> of pexcel <code>Byte</code>
+ */
+ private Vector functionEncoder(Token t) {
+ Vector tmpByteArray = new Vector();
+
+ int id = t.getTokenID();
+ if(t.getTokenType()==ParseToken.TOKEN_FUNCTION_VARIABLE) {
+ tmpByteArray.add(new Byte((byte)TokenConstants.TFUNCVAR));
+ tmpByteArray.add(new Byte((byte)t.getNumArgs()));
+ } else {
+ tmpByteArray.add(new Byte((byte)TokenConstants.TFUNC));
+ }
+
+ tmpByteArray.add(new Byte((byte)id));
+ tmpByteArray.add(new Byte((byte)(id>>8)));
+ return tmpByteArray;
+ }
+
+
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenFactory.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenFactory.java
new file mode 100644
index 000000000000..e745c7c0f970
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/TokenFactory.java
@@ -0,0 +1,118 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+import org.openoffice.xmerge.util.Debug;
+
+/**
+ * This is the Factory class responsible for creating a <code>Token</code>.
+ * It has three methods for returning three different types of Tokens
+ * (Operator, Operand and Function).
+ * This utility class is used by either the <code>FormulaParser</code> or the
+ * <code>FormulaDecoder</code>.
+ */
+public class TokenFactory {
+
+ private OperatorLookup operatorLookup;
+ private OperandLookup operandLookup;
+ private FunctionLookup fl;
+
+ /**
+ * Default Constructor
+ */
+ public TokenFactory() {
+ operatorLookup = new OperatorLookup();
+ operandLookup = new OperandLookup();
+ fl = new FunctionLookup();
+ }
+
+ /**
+ * The Factory method for creating function Tokens
+ *
+ * @return The created <code>Token</code>
+ */
+ public Token getFunctionToken(String s, int args) {
+ Token t = null;
+ // We will have to fix this later to include fixed function tokens
+ // Also will need to handle errors where functions names are incorrect???
+ Debug.log(Debug.TRACE,"TokenFactory creating function Token : " + s);
+ try {
+ t = new Token(s, ParseToken.TOKEN_FUNCTION_VARIABLE, fl.getIDFromString(s), args);
+ } catch (UnsupportedFunctionException eFn) {
+
+ Debug.log(Debug.ERROR, eFn.getMessage());
+ }
+ return t;
+ }
+
+ /**
+ * The Factory method for creating operator Tokens
+ *
+ * @return The created <code>Token</code>
+ */
+ public Token getOperatorToken(String s, int args) {
+
+ Token t = null;
+
+ Debug.log(Debug.TRACE,"TokenFactory creating operator Token : " + s);
+ try {
+ if(args==1) {
+ if(s.equals("+")) {
+ t = new Token(s, ParseToken.TOKEN_OPERATOR, operatorLookup.getIDFromString("UNARY_PLUS"), args);
+ } else if (s.equals("-")) {
+ t = new Token(s, ParseToken.TOKEN_OPERATOR, operatorLookup.getIDFromString("UNARY_MINUS"), args);
+ } else {
+ t = new Token(s, ParseToken.TOKEN_OPERATOR, operatorLookup.getIDFromString(s), args);
+ }
+ } else {
+ t = new Token(s, ParseToken.TOKEN_OPERATOR, operatorLookup.getIDFromString(s), args);
+ }
+ } catch (UnsupportedFunctionException eFn) {
+ Debug.log(Debug.ERROR, eFn.getMessage());
+ }
+ return t;
+ }
+
+ /**
+ * The Factory method for creating Operand Tokens
+ *
+ * @return The created <code>Token</code>
+ */
+ public Token getOperandToken(String s, String type) {
+ Token t = null;
+
+ Debug.log(Debug.TRACE,"TokenFactory creating operand (" + type + ") Token : " + s);
+ try {
+ t = new Token(s, ParseToken.TOKEN_OPERAND, operandLookup.getIDFromString(type), 0);
+ } catch (UnsupportedFunctionException eFn) {
+ Debug.log(Debug.ERROR, eFn.getMessage());
+ }
+
+ return t;
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/UnsupportedFunctionException.java b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/UnsupportedFunctionException.java
new file mode 100644
index 000000000000..ca2794d3f73d
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/UnsupportedFunctionException.java
@@ -0,0 +1,40 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula;
+
+/*
+ * Exception thrown when a function specified in a calc formula has no equivalent in Pocket Excel
+ *
+ * @author : Mike Hayes
+ */
+
+public class UnsupportedFunctionException extends Exception {
+ UnsupportedFunctionException(String message) {
+ super(message);
+ }
+}
diff --git a/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/package.html b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/package.html
new file mode 100644
index 000000000000..6239c2b5b625
--- /dev/null
+++ b/xmerge/source/pexcel/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/formula/package.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+ <!--
+ #*************************************************************************
+ #
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ Copyright 2000, 2010 Oracle and/or its affiliates.
+
+ OpenOffice.org - a multi-platform office productivity suite
+
+ This file is part of OpenOffice.org.
+
+ OpenOffice.org is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 3
+ only, as published by the Free Software Foundation.
+
+ OpenOffice.org is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License version 3 for more details
+ (a copy is included in the LICENSE file that accompanied this code).
+
+ You should have received a copy of the GNU Lesser General Public License
+ version 3 along with OpenOffice.org. If not, see
+ <http://www.openoffice.org/license.html>
+ for a copy of the LGPLv3 License.
+
+ #*************************************************************************
+ -->
+
+ <title>org.openoffice.xmerge.converter.xml.sxc.pexcel.records.formula package</title>
+
+</head>
+ <body bgcolor="white">
+
+<p> This package contains the classes necessary for converting pexcel formula
+to and from StarCalc Formula.</p>
+
+</body>
+</html>