Framework to set the class of a token

git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@352651 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Avik Sengupta 2002-05-27 21:00:12 +00:00
parent d52ae71cde
commit b35ab14e42
20 changed files with 339 additions and 142 deletions

View File

@ -125,4 +125,6 @@ public class AddPtg
return buffer.toString();
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
}

View File

@ -243,5 +243,8 @@ public class Area3DPtg extends Ptg
return result;
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
}

View File

@ -131,7 +131,7 @@ public class AreaPtg
}
public void writeBytes(byte [] array, int offset) {
array[offset] = sid;
array[offset] = (byte) (sid + ptgClass);
LittleEndian.putShort(array,offset+1,field_1_first_row);
LittleEndian.putShort(array,offset+3,field_2_last_row);
LittleEndian.putShort(array,offset+5,field_3_first_column);
@ -309,4 +309,8 @@ public class AreaPtg
(new CellReference(getLastRow(),getLastColumn(),!isLastRowRelative(),!isLastColRelative())).toString();
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_REF;
}
}

View File

@ -211,5 +211,5 @@ public class AttrPtg
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
}

View File

@ -96,4 +96,7 @@ public class ExpPtg
{
return "NO IDEA SHARED FORMULA EXP PTG";
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
}

View File

@ -79,6 +79,12 @@ import java.io.File;
*/
public class FormulaParser {
public static int FORMULA_TYPE_CELL = 0;
public static int FORMULA_TYPE_SHARED = 1;
public static int FORMULA_TYPE_ARRAY =2;
public static int FORMULA_TYPE_CONDFOMRAT = 3;
public static int FORMULA_TYPE_NAMEDRANGE = 4;
private String formulaString;
private int pointer=0;
@ -193,18 +199,16 @@ public class FormulaParser {
/** Get an Identifier */
private String GetName() {
String Token;
Token = "";
StringBuffer Token = new StringBuffer();
if (!IsAlpha(Look)) {
Expected("Name");
}
while (IsAlNum(Look)) {
Token = Token + Character.toUpperCase(Look);
Token = Token.append(Character.toUpperCase(Look));
GetChar();
}
SkipWhite();
return Token;
return Token.toString();
}
@ -304,7 +308,10 @@ public class FormulaParser {
return;
} else if (IsAlpha(Look)){
Ident();
}else{
} else if(Look == '"') {
StringLiteral();
} else {
String number = GetNum();
if (Look=='.') {
Match('.');
@ -317,6 +324,12 @@ public class FormulaParser {
}
}
private void StringLiteral() {
Match('"');
String name= GetName();
Match('"');
tokens.add(new StringPtg(name));
}
/** Recognize and Translate a Multiply */
private void Multiply(){
@ -429,13 +442,89 @@ end;
* a result of the parsing
*/
public Ptg[] getRPNPtg() {
synchronized (tokens) {
if (tokens == null) throw new IllegalStateException("Please parse a string before trying to access the parse result");
Ptg[] retval = new Ptg[tokens.size()];
return (Ptg[]) tokens.toArray(retval);
}
return getRPNPtg(FORMULA_TYPE_CELL);
}
public Ptg[] getRPNPtg(int formulaType) {
Node node = createTree();
setRootLevelRVA(node, formulaType);
setParameterRVA(node,formulaType);
return (Ptg[]) tokens.toArray(new Ptg[0]);
}
private void setRootLevelRVA(Node n, int formulaType) {
//Pg 16, excelfileformat.pdf @ openoffice.org
Ptg p = (Ptg) n.getValue();
if (formulaType == this.FORMULA_TYPE_NAMEDRANGE) {
if (p.getDefaultOperandClass() == Ptg.CLASS_REF) {
setClass(n,Ptg.CLASS_REF);
} else {
setClass(n,Ptg.CLASS_ARRAY);
}
} else {
setClass(n,Ptg.CLASS_VALUE);
}
}
private void setParameterRVA(Node n, int formulaType) {
Ptg p = (Ptg) n.getValue();
if (p instanceof FunctionPtg) {
int numOperands = n.getNumChildren();
for (int i =0;i<n.getNumChildren();i++) {
setParameterRVA(n.getChild(i),((FunctionPtg)p).getParameterClass(i),formulaType);
if (n.getChild(i).getValue() instanceof FunctionPtg) {
setParameterRVA(n.getChild(i),formulaType);
}
}
} else {
for (int i =0;i<n.getNumChildren();i++) {
setParameterRVA(n.getChild(i),formulaType);
}
}
}
private void setParameterRVA(Node n, int expectedClass,int formulaType) {
Ptg p = (Ptg) n.getValue();
if (expectedClass == Ptg.CLASS_REF) { //pg 15, table 1
if (p.getDefaultOperandClass() == Ptg.CLASS_REF ) {
setClass(n, Ptg.CLASS_REF);
}
if (p.getDefaultOperandClass() == Ptg.CLASS_VALUE) {
if (formulaType==FORMULA_TYPE_CELL || formulaType == FORMULA_TYPE_SHARED) {
setClass(n,Ptg.CLASS_VALUE);
} else {
setClass(n,Ptg.CLASS_ARRAY);
}
}
if (p.getDefaultOperandClass() == Ptg.CLASS_ARRAY ) {
setClass(n, Ptg.CLASS_ARRAY);
}
} else if (expectedClass == Ptg.CLASS_VALUE) { //pg 15, table 2
if (formulaType == FORMULA_TYPE_NAMEDRANGE) {
setClass(n,Ptg.CLASS_ARRAY) ;
} else {
setClass(n,Ptg.CLASS_VALUE);
}
} else { //Array class, pg 16.
if (p.getDefaultOperandClass() == Ptg.CLASS_VALUE &&
(formulaType==FORMULA_TYPE_CELL || formulaType == FORMULA_TYPE_SHARED)) {
setClass(n,Ptg.CLASS_VALUE);
} else {
setClass(n,Ptg.CLASS_ARRAY);
}
}
}
private void setClass(Node n, byte theClass) {
Ptg p = (Ptg) n.getValue();
if (p instanceof FunctionPtg || !(p instanceof OperationPtg)) {
p.setClass(theClass);
} else {
for (int i =0;i<n.getNumChildren();i++) {
setClass(n.getChild(i),theClass);
}
}
}
/**
* Convience method which takes in a list then passes it to the other toFormulaString
* signature
@ -459,6 +548,7 @@ end;
String[] operands;
for (int i=0;i<numPtgs;i++) {
if (ptgs[i] instanceof OperationPtg) {
// Excel allows to have AttrPtg at position 0 (such as Blanks) which
// do not have any operands. Skip them.
if(i > 0) {
@ -479,6 +569,31 @@ end;
return (String) stack.pop(); //TODO: catch stack underflow and throw parse exception.
}
private Node createTree() {
java.util.Stack stack = new java.util.Stack();
int numPtgs = tokens.size();
OperationPtg o;
int numOperands;
Node[] operands;
for (int i=0;i<numPtgs;i++) {
if (tokens.get(i) instanceof OperationPtg) {
o = (OperationPtg) tokens.get(i);
numOperands = o.getNumberOfOperands();
operands = new Node[numOperands];
for (int j=0;j<numOperands;j++) {
operands[numOperands-j-1] = (Node) stack.pop();
}
Node result = new Node(o);
result.setChildren(operands);
stack.push(result);
} else {
stack.push(new Node((Ptg)tokens.get(i)));
}
}
return (Node) stack.pop();
}
/** toString on the parser instance returns the RPN ordered list of tokens
* Useful for testing
*/
@ -491,5 +606,17 @@ end;
return buf.toString();
}
}
class Node {
private Ptg value=null;
private Node[] children=new Node[0];
private int numChild=0;
public Node(Ptg val) {
value = val;
}
public void setChildren(Node[] child) {children = child;numChild=child.length;}
public int getNumChildren() {return numChild;}
public Node getChild(int number) {return children[number];}
public Ptg getValue() {return value;}
}

View File

@ -9,15 +9,15 @@ import org.apache.poi.util.BinaryTree;
* This class provides functions with variable arguments.
* @author Avik Sengupta
* @author Andrew C. Oliver (acoliver at apache dot org)
* @version
*/
public class FunctionPtg extends OperationPtg {
public final static short sid = 0x22;
private final static int SIZE = 4;
private static BinaryTree map = produceHash();
static { map=produceHash();}
private static Object[][] functionData = produceFunctionData();
private byte returnClass;
private byte[] paramClass;
private byte field_1_num_args;
private short field_2_fnc_index;
@ -30,7 +30,6 @@ public class FunctionPtg extends OperationPtg {
offset++;
field_1_num_args = data[ offset + 0 ];
field_2_fnc_index = LittleEndian.getShort(data,offset + 1 );
}
/**
@ -39,7 +38,13 @@ public class FunctionPtg extends OperationPtg {
protected FunctionPtg(String pName, byte pNumOperands) {
field_1_num_args = pNumOperands;
field_2_fnc_index = lookupIndex(pName);
try{
returnClass = ( (Byte) functionData[field_2_fnc_index][0]).byteValue();
paramClass = (byte[]) functionData[field_2_fnc_index][1];
} catch (NullPointerException npe ) {
returnClass = Ptg.CLASS_VALUE;
paramClass = new byte[] {Ptg.CLASS_VALUE};
}
}
public String toString() {
@ -89,7 +94,7 @@ public class FunctionPtg extends OperationPtg {
public void writeBytes(byte[] array, int offset) {
array[offset+0]=sid;
array[offset+0]=(byte) (sid + ptgClass);
array[offset+1]=field_1_num_args;
LittleEndian.putShort(array,offset+2,field_2_fnc_index);
}
@ -99,11 +104,11 @@ public class FunctionPtg extends OperationPtg {
}
private String lookupName(short index) {
return ((String)map.get(new Integer(index))); //for now always return "SUM"
return ((String)map.get(new Integer(index)));
}
private short lookupIndex(String name) {
return (short)((Integer)map.getKeyForValue(name)).intValue(); //for now just return SUM everytime...
return (short)((Integer)map.getKeyForValue(name)).intValue();
}
/**
@ -465,4 +470,50 @@ public class FunctionPtg extends OperationPtg {
return dmap;
}
private static Object[][] produceFunctionData() {
Object [][] functionData = new Object[368][2];
functionData[0][0]=new Byte(Ptg.CLASS_VALUE);functionData[0][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[2][0]=new Byte(Ptg.CLASS_VALUE);functionData[2][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[3][0]=new Byte(Ptg.CLASS_VALUE);functionData[3][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[4][0]=new Byte(Ptg.CLASS_VALUE);functionData[4][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[5][0]=new Byte(Ptg.CLASS_VALUE);functionData[5][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[6][0]=new Byte(Ptg.CLASS_VALUE);functionData[6][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[7][0]=new Byte(Ptg.CLASS_VALUE);functionData[7][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[8][0]=new Byte(Ptg.CLASS_VALUE);functionData[8][1]=new byte[] {Ptg.CLASS_REF};
functionData[9][0]=new Byte(Ptg.CLASS_VALUE);functionData[9][1]=new byte[] {Ptg.CLASS_REF};
functionData[10][0]=new Byte(Ptg.CLASS_VALUE);functionData[10][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[11][0]=new Byte(Ptg.CLASS_VALUE);functionData[11][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[12][0]=new Byte(Ptg.CLASS_VALUE);functionData[12][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[13][0]=new Byte(Ptg.CLASS_VALUE);functionData[13][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[14][0]=new Byte(Ptg.CLASS_VALUE);functionData[14][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[15][0]=new Byte(Ptg.CLASS_VALUE);functionData[15][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[16][0]=new Byte(Ptg.CLASS_VALUE);functionData[16][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[17][0]=new Byte(Ptg.CLASS_VALUE);functionData[17][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[18][0]=new Byte(Ptg.CLASS_VALUE);functionData[18][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[19][0]=new Byte(Ptg.CLASS_VALUE);functionData[19][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[20][0]=new Byte(Ptg.CLASS_VALUE);functionData[20][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[21][0]=new Byte(Ptg.CLASS_VALUE);functionData[21][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[22][0]=new Byte(Ptg.CLASS_VALUE);functionData[22][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[23][0]=new Byte(Ptg.CLASS_VALUE);functionData[23][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[24][0]=new Byte(Ptg.CLASS_VALUE);functionData[24][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[25][0]=new Byte(Ptg.CLASS_VALUE);functionData[25][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[26][0]=new Byte(Ptg.CLASS_VALUE);functionData[26][1]=new byte[] {Ptg.CLASS_VALUE};
functionData[27][0]=new Byte(Ptg.CLASS_VALUE);functionData[27][1]=new byte[] {Ptg.CLASS_VALUE};
return functionData;
}
public byte getDefaultOperandClass() {
return returnClass;
}
protected byte getParameterClass(int index) {
try {
return paramClass[index];
} catch (ArrayIndexOutOfBoundsException aioobe) {
return paramClass[paramClass.length - 1];
}
}
}

View File

@ -114,5 +114,5 @@ public class IntPtg
{
return "" + getValue();
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
}

View File

@ -120,4 +120,5 @@ public class MemErrPtg
{
return "ERR#";
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
}

View File

@ -106,4 +106,6 @@ public class NamePtg
{
return "NO IDEA - NAME";
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
}

View File

@ -113,6 +113,6 @@ public class NumberPtg
{
return "" + getValue();
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
}

View File

@ -88,4 +88,6 @@ public abstract class OperationPtg extends Ptg
*/
public abstract int getNumberOfOperands();
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
}

View File

@ -114,5 +114,7 @@ public class ParenthesisPtg
return "("+operands[0]+")";
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
}

View File

@ -110,8 +110,6 @@ public class PowerPtg
return "^";
}
public String toFormulaString(String[] operands) {
StringBuffer buffer = new StringBuffer();

View File

@ -66,6 +66,7 @@ import java.util.ArrayList;
/**
*
* @author andy
* @author avik
*/
public abstract class Ptg
@ -125,53 +126,17 @@ public abstract class Ptg
}
*/
/*
private static List ptgsToList(Class [] ptgs)
{
List result = new ArrayList();
Constructor constructor;
for (int i = 0; i < ptgs.length; i++)
{
Class ptg = null;
ptg = ptgs[ i ];
try
{
constructor = ptg.getConstructor(new Class[]
{
byte [].class, int.class
});
}
catch (Exception illegalArgumentException)
{
throw new RuntimeException(
"Now that didn't work nicely at all (couldn't do that there list of ptgs)");
}
result.add(constructor);
}
return result;
}*/
public static Ptg createPtg(byte [] data, int offset)
{
byte id = data[ offset + 0 ];
Ptg retval = null;
final int refRef = ReferencePtg.sid - 0x20;
final int arrayRef = ReferencePtg.sid + 0x20;
final int valueFunc = FunctionPtg.sid + 0x20;
final int arrayFunc = FunctionPtg.sid + 0x40;
final int refArea = AreaPtg.sid-0x20;
final int arrayArea = AreaPtg.sid+0x20;
final byte valueRef = ReferencePtg.sid + 0x20;
final byte arrayRef = ReferencePtg.sid + 0x40;
final byte valueFunc = FunctionPtg.sid + 0x20;
final byte arrayFunc = FunctionPtg.sid + 0x40;
final byte valueArea = AreaPtg.sid + 0x20;
final byte arrayArea = AreaPtg.sid + 0x40;
switch (id)
{
@ -207,7 +172,12 @@ public abstract class Ptg
case AreaPtg.sid :
retval = new AreaPtg(data, offset);
break;
case valueArea:
retval = new AreaPtg(data, offset);
break;
case arrayArea:
retval = new AreaPtg(data, offset);
break;
case MemErrPtg.sid :
retval = new MemErrPtg(data, offset);
break;
@ -219,11 +189,9 @@ public abstract class Ptg
case ReferencePtg.sid :
retval = new ReferencePtg(data, offset);
break;
case refRef :
case valueRef :
retval = new ReferencePtg(data, offset);
break;
case arrayRef :
retval = new ReferencePtg(data, offset);
break;
@ -239,7 +207,6 @@ public abstract class Ptg
case valueFunc :
retval = new FunctionPtg(data, offset);
break;
case arrayFunc :
retval = new FunctionPtg(data, offset);
break;
@ -275,7 +242,15 @@ public abstract class Ptg
+ Integer.toHexString(( int ) id)
+ " (" + ( int ) id + ")");
}
return retval;
if (id > 0x60) {
retval.setClass(CLASS_ARRAY);
} else if (id > 0x40) {
retval.setClass(CLASS_VALUE);
} else
retval.setClass(CLASS_REF);
return retval;
}
public abstract int getSize();
@ -310,5 +285,19 @@ public abstract class Ptg
return retval;
}
public static final byte CLASS_REF = 0x00;
public static final byte CLASS_VALUE = 0x20;
public static final byte CLASS_ARRAY = 0x40;
protected byte ptgClass = CLASS_REF; //base ptg
public void setClass(byte thePtgClass) {
ptgClass = thePtgClass;
}
public abstract byte getDefaultOperandClass();
}

View File

@ -1,4 +1,5 @@
/* ====================================================================
* The Apache Software License, Version 1.1
*
@ -174,4 +175,6 @@ public class Ref3DPtg extends Ptg {
return result;
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
}

View File

@ -66,18 +66,15 @@ import org.apache.poi.util.BitField;
import org.apache.poi.hssf.util.CellReference;
/**
* ValueReferencePtg - handles references (such as A1, A2, IA4) - Should also
* be made to handle relative versus absolute references but I don't know enough
* about using them in excel to know if its correct. Seems inverted to me.
* FIXME = correct abs vs relative references
* ReferencePtg - handles references (such as A1, A2, IA4)
* @author Andrew C. Oliver (acoliver@apache.org)
*/
public class ReferencePtg extends Ptg
{
private final static int SIZE = 5;
//public final static byte sid = 0x24;
public final static byte sid = 0x44;
public final static byte sid = 0x24;
//public final static byte sid = 0x44;
private short field_1_row;
private short field_2_col;
private BitField rowRelative = new BitField(0x8000);
@ -120,7 +117,7 @@ public class ReferencePtg extends Ptg
public void writeBytes(byte [] array, int offset)
{
array[offset] = sid;
array[offset] = (byte) (sid + ptgClass);
LittleEndian.putShort(array,offset+1,field_1_row);
LittleEndian.putShort(array,offset+3,field_2_col);
}
@ -183,4 +180,9 @@ public class ReferencePtg extends Ptg
//TODO -- should we store a cellreference instance in this ptg?? but .. memory is an issue, i believe!
return (new CellReference(getRow(),getColumn(),!isRowRelative(),!isColRelative())).toString();
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_REF;
}
}

View File

@ -114,6 +114,9 @@ public class StringPtg
{
return getValue();
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
}

View File

@ -95,4 +95,7 @@ public class UnknownPtg
{
return "UNKNOWN";
}
public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
}

View File

@ -768,6 +768,8 @@ extends TestCase {
c.setCellFormula("AVERAGE(A2:A3)");
c=r.createCell( (short) 4);
c.setCellFormula("POWER(A2,A3)");
c=r.createCell( (short) 5);
c.setCellFormula("SIN(A2)");
r = s.createRow((short) 1);c=r.createCell( (short) 0); c.setCellValue(2.0);
r = s.createRow((short) 2);c=r.createCell( (short) 0); c.setCellValue(3.0);