added new class from Avik Sengupta
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@352434 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2c14cfee1d
commit
910c8736cb
450
src/java/org/apache/poi/hssf/record/formula/FormulaParser.java
Normal file
450
src/java/org/apache/poi/hssf/record/formula/FormulaParser.java
Normal file
@ -0,0 +1,450 @@
|
||||
|
||||
/* ====================================================================
|
||||
* The Apache Software License, Version 1.1
|
||||
*
|
||||
* Copyright (c) 2002 The Apache Software Foundation. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. The end-user documentation included with the redistribution,
|
||||
* if any, must include the following acknowledgment:
|
||||
* "This product includes software developed by the
|
||||
* Apache Software Foundation (http://www.apache.org/)."
|
||||
* Alternately, this acknowledgment may appear in the software itself,
|
||||
* if and wherever such third-party acknowledgments normally appear.
|
||||
*
|
||||
* 4. The names "Apache" and "Apache Software Foundation" and
|
||||
* "Apache POI" must not be used to endorse or promote products
|
||||
* derived from this software without prior written permission. For
|
||||
* written permission, please contact apache@apache.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Apache",
|
||||
* "Apache POI", nor may "Apache" appear in their name, without
|
||||
* prior written permission of the Apache Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by many
|
||||
* individuals on behalf of the Apache Software Foundation. For more
|
||||
* information on the Apache Software Foundation, please see
|
||||
* <http://www.apache.org/>.
|
||||
*/
|
||||
|
||||
|
||||
package org.apache.poi.hssf.record.formula;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL code to parse formulas back and forth between RPN and not
|
||||
*
|
||||
* @author Avik Sengupta <lists@aviksengupta.com>
|
||||
*/
|
||||
public class FormulaParser {
|
||||
|
||||
private String formulaString;
|
||||
private int pointer=0;
|
||||
|
||||
private Stack operationsList = new java.util.Stack();
|
||||
private Stack operandsList = new java.util.Stack();
|
||||
private List result = new ArrayList();
|
||||
private int numParen;
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Constant Declarations }
|
||||
|
||||
private static char TAB = '\t';
|
||||
private static char CR = '\n';
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Variable Declarations }
|
||||
|
||||
private char Look; //{ Lookahead Character }
|
||||
|
||||
public FormulaParser(String formula){
|
||||
formulaString = formula;
|
||||
pointer=0;
|
||||
}
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Read New Character From Input Stream }
|
||||
|
||||
private void GetChar() {
|
||||
Look=formulaString.charAt(pointer++);
|
||||
System.out.println("Got char: "+Look);
|
||||
}
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Report an Error }
|
||||
|
||||
private void Error(String s) {
|
||||
System.out.println("Error: "+s);
|
||||
}
|
||||
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Report Error and Halt }
|
||||
|
||||
private void Abort(String s) {
|
||||
Error(s);
|
||||
//System.exit(1); //throw exception??
|
||||
throw new RuntimeException("Cannot Parse, sorry");
|
||||
}
|
||||
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Report What Was Expected }
|
||||
|
||||
private void Expected(String s) {
|
||||
Abort(s + " Expected");
|
||||
}
|
||||
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Recognize an Alpha Character }
|
||||
|
||||
private boolean IsAlpha(char c) {
|
||||
return Character.isLetter(c);
|
||||
//return UpCase(c) in ['A'..'Z'];
|
||||
}
|
||||
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Recognize a Decimal Digit }
|
||||
|
||||
private boolean IsDigit(char c) {
|
||||
System.out.println("Checking digit for"+c);
|
||||
return Character.isDigit(c);
|
||||
|
||||
//return ("0123456789".indexOf( (int) c) != 0)//c in ['0'..'9'];
|
||||
}
|
||||
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Recognize an Alphanumeric }
|
||||
|
||||
private boolean IsAlNum(char c) {
|
||||
return (IsAlpha(c) || IsDigit(c));
|
||||
}
|
||||
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Recognize an Addop }
|
||||
|
||||
private boolean IsAddop( char c) {
|
||||
return (c =='+' || c =='-');
|
||||
}
|
||||
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Recognize White Space }
|
||||
|
||||
private boolean IsWhite( char c) {
|
||||
return (c ==' ' || c== TAB);
|
||||
}
|
||||
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Skip Over Leading White Space }
|
||||
|
||||
private void SkipWhite() {
|
||||
while (IsWhite(Look)) {
|
||||
GetChar();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Match a Specific Input Character }
|
||||
|
||||
private void Match(char x) {
|
||||
if (Look != x) {
|
||||
Expected("" + x + "");
|
||||
}else {
|
||||
GetChar();
|
||||
SkipWhite();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Get an Identifier }
|
||||
|
||||
private String GetName() {
|
||||
String Token;
|
||||
Token = "";
|
||||
if (!IsAlpha(Look)) {
|
||||
Expected("Name");
|
||||
}
|
||||
while (IsAlNum(Look)) {
|
||||
Token = Token + Character.toUpperCase(Look);
|
||||
GetChar();
|
||||
}
|
||||
|
||||
SkipWhite();
|
||||
return Token;
|
||||
}
|
||||
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Get a Number }
|
||||
|
||||
private String GetNum() {
|
||||
String Value ="";
|
||||
if (!IsDigit(Look)) Expected("Integer");
|
||||
while (IsDigit(Look)){
|
||||
Value = Value + Look;
|
||||
GetChar();
|
||||
}
|
||||
SkipWhite();
|
||||
return Value;
|
||||
}
|
||||
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Output a String with Tab }
|
||||
|
||||
private void Emit(String s){
|
||||
System.out.print(TAB+s);
|
||||
}
|
||||
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Output a String with Tab and CRLF }
|
||||
|
||||
private void EmitLn(String s) {
|
||||
Emit(s);
|
||||
System.out.println();;
|
||||
}
|
||||
|
||||
|
||||
//{---------------------------------------------------------------}
|
||||
//{ Parse and Translate a Identifier }
|
||||
|
||||
private void Ident() {
|
||||
String Name;
|
||||
Name = GetName();
|
||||
if (Look == '('){
|
||||
Match('(');
|
||||
//Expression() -- add this!
|
||||
Match(')');
|
||||
//this is the end of the function
|
||||
//EmitLn("BSR " + Name);
|
||||
} else {
|
||||
//EmitLn("MOVE " + Name + "(PC),D0b");
|
||||
//this can be either a cell ref or a named range !!
|
||||
|
||||
boolean cellRef = true ; //we should probably do it with reg exp??
|
||||
if (cellRef) {
|
||||
operationsList.add(new ValueReferencePtg()); //TODO we need to pass in Name somewhere
|
||||
}else {
|
||||
//handle after named range is integrated!!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//{---------------------------------------------------------------}
|
||||
//{ Parse and Translate a Math Factor }
|
||||
|
||||
//procedure Expression; Forward;
|
||||
|
||||
private void Factor() {
|
||||
if (Look == '(' ) {
|
||||
Match('(');
|
||||
operationsList.add(new ParenthesisPtg());
|
||||
Expression();
|
||||
Match(')');
|
||||
operationsList.add(new ParenthesisPtg());
|
||||
return;
|
||||
} else if (IsAlpha(Look)){
|
||||
Ident();
|
||||
}else{
|
||||
//EmitLn("MOVE #" + GetNum() + ",D0");
|
||||
IntPtg p = new IntPtg();
|
||||
p.setValue(Short.parseShort(GetNum()));
|
||||
operandsList.add(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Recognize and Translate a Multiply }
|
||||
|
||||
private void Multiply(){
|
||||
Match('*');
|
||||
Factor();
|
||||
operationsList.add(new MultiplyPtg());
|
||||
//EmitLn("MULS (SP)+,D0");
|
||||
}
|
||||
|
||||
|
||||
//{-------------------------------------------------------------}
|
||||
//{ Recognize and Translate a Divide }
|
||||
|
||||
private void Divide() {
|
||||
Match('/');
|
||||
Factor();
|
||||
operationsList.add(new DividePtg());
|
||||
//EmitLn("MOVE (SP)+,D1");
|
||||
//EmitLn("EXS.L D0");
|
||||
//EmitLn("DIVS D1,D0");
|
||||
}
|
||||
|
||||
|
||||
//{---------------------------------------------------------------}
|
||||
//{ Parse and Translate a Math Term }
|
||||
|
||||
private void Term(){
|
||||
Factor();
|
||||
while (Look == '*' || Look == '/' ) {
|
||||
//EmitLn("MOVE D0,-(SP)");
|
||||
///TODO do we need to do anything here??
|
||||
if (Look == '*') Multiply();
|
||||
if (Look == '/') Divide();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Recognize and Translate an Add }
|
||||
|
||||
private void Add() {
|
||||
Match('+');
|
||||
Term();
|
||||
//EmitLn("ADD (SP)+,D0");
|
||||
operationsList.add(new AddPtg());
|
||||
}
|
||||
|
||||
|
||||
//{-------------------------------------------------------------}
|
||||
//{ Recognize and Translate a Subtract }
|
||||
|
||||
private void Subtract() {
|
||||
Match('-');
|
||||
Term();
|
||||
operationsList.add(new SubtractPtg());
|
||||
//EmitLn("SUB (SP)+,D0");
|
||||
//EmitLn("NEG D0");
|
||||
}
|
||||
|
||||
|
||||
//{---------------------------------------------------------------}
|
||||
//{ Parse and Translate an Expression }
|
||||
|
||||
private void Expression() {
|
||||
if (IsAddop(Look)) {
|
||||
EmitLn("CLR D0"); //unaryAdd ptg???
|
||||
} else {
|
||||
Term();
|
||||
}
|
||||
while (IsAddop(Look)) {
|
||||
EmitLn("MOVE D0,-(SP)");
|
||||
if ( Look == '+' ) Add();
|
||||
if (Look == '-') Subtract();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Parse and Translate an Assignment Statement }
|
||||
/**
|
||||
procedure Assignment;
|
||||
var Name: string[8];
|
||||
begin
|
||||
Name := GetName;
|
||||
Match('=');
|
||||
Expression;
|
||||
EmitLn('LEA ' + Name + '(PC),A0');
|
||||
EmitLn('MOVE D0,(A0)')
|
||||
end;
|
||||
**/
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Initialize }
|
||||
|
||||
private void Init() {
|
||||
GetChar();
|
||||
SkipWhite();
|
||||
}
|
||||
|
||||
public void parse() {
|
||||
Init();
|
||||
Expression();
|
||||
//now tokenisation is done .. convert to RPN!!
|
||||
tokenToRPN();
|
||||
}
|
||||
|
||||
private void tokenToRPN() {
|
||||
OperationPtg op;
|
||||
Ptg operand;
|
||||
int numOper = 0;
|
||||
int numOnStack = 0;
|
||||
result.add(operandsList.pop()); numOnStack++;
|
||||
|
||||
while (!operationsList.isEmpty()) {
|
||||
op = (OperationPtg) operationsList.pop();
|
||||
if (op instanceof ParenthesisPtg) {
|
||||
// do something smart
|
||||
}
|
||||
|
||||
|
||||
for (numOper = op.getNumberOfOperands();numOper>0;numOper--) {
|
||||
if (numOnStack==0) {
|
||||
result.add(operandsList.pop());//numOnStack++;
|
||||
} else {
|
||||
numOnStack--;
|
||||
}
|
||||
}
|
||||
result.add(op);
|
||||
numOnStack++;
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i=0;i<result.size();i++) {
|
||||
buf.append( ( (Ptg)result.get(i)).toFormulaString());
|
||||
buf.append(' ');
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
//{--------------------------------------------------------------}
|
||||
//{ Main Program for testing}
|
||||
public static void main(String[] argv) {
|
||||
FormulaParser fp = new FormulaParser(argv[0]+";");
|
||||
fp.parse();
|
||||
System.out.println(fp.toString());
|
||||
|
||||
//If Look <> CR then Expected('NewLine');
|
||||
}
|
||||
//{--------------------------------------------------------------}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user