As per my promise, here is the stuff that lets us parse integers and operators 
(+-*/) and brackets into RPN order. 

Actually the patch is in two parts. 

1. o.a.p.h.r.formula.FormulaParser :- this class now completely parses a 
formula and returns a rpn order list of Ptgs. The rpn conversion is implicit in 
the parsing grammer, thus there is no seperation "toRPN" method. try calling 
this class with (2+3)*4 and 2+3*4 to test its capabilities. This class is built 
using the philosophy of all parsing (tokenising) in one class -- the actual 
conversion to hex is of course in each ptg impl. 

2. o.a.p.h.r.formula.Ptg :- a new method List ptgToRpn(List) that converts a 
list of infix order ptgs to rpn order ptgs. This is what one would do if we 
follow Andy's idea of each Ptg  being responsible for tokenising the relevent 
part of the formula string. I havent tested this too much since i would have to 
write code in each ptg to test it. however, you can try it for 2+3, which works 
fine , since the Andy has already written up the IntPtg and AddPtg. I've added 
a method to the OperationsPtg interface to to return precedence.

Since i havent yet made up my mind on either of the two approaches, i will 
parallely experiment on both tracks, until circumstances or good sense overtake 
me.

With the above level of functionality, we should be able to integrate formulas 
consisting of literals and operators into poi. The next hill to climb of course 
is functions, and the next mountain is cell references.

Regards
-
Avik
 
? .nbattrs
? formula.patch
Index: DividePtg.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/DividePtg.java,v

retrieving revision 1.1.1.1
diff -u -r1.1.1.1 DividePtg.java
--- DividePtg.java      31 Jan 2002 02:23:44 -0000      1.1.1.1
+++ DividePtg.java      21 Apr 2002 20:41:07 -0000
@@ -118,4 +118,11 @@
         buffer.append(operands[ 1 ].toFormulaString());
         return buffer.toString();
     }
+     public int getPrecedence() {
+        return 4;
+    }
+    
+    public int getStringLength() {
+        return 1;
+    }
 }
Index: FormulaParser.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/FormulaParser.java,v

retrieving revision 1.1
diff -u -r1.1 FormulaParser.java
--- FormulaParser.java  17 Apr 2002 23:06:49 -0000      1.1
+++ FormulaParser.java  21 Apr 2002 20:41:08 -0000
@@ -61,17 +61,25 @@
 import java.util.Stack;
 
 /**
- * EXPERIMENTAL code to parse formulas back and forth between RPN and not
+ * EXPERIMENTAL 
  *
  * @author Avik Sengupta <[EMAIL PROTECTED]>
+ *
+ * This class parses a formula string into a List of tokens in RPN order
+ * Inspired by 
+ *  Lets Build a Compiler, by Jack Crenshaw
+ * BNF for the formula expression is :
+ * <expression> ::= <term> [<addop> <term>]*
+ * <term> ::= <factor>  [ <mulop> <factor ]*
+ * <factor> ::= <number> | (<expression>) | <cellRef> 
  */
 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 tokens = new java.util.Stack();
+    //private Stack tokens = new java.util.Stack();
     private List result = new ArrayList();
     private int numParen;
     
@@ -160,7 +168,6 @@
         return (c =='+' || c =='-');
     }
     
-    
     //{--------------------------------------------------------------}
     //{ Recognize White Space }
     
@@ -261,7 +268,7 @@
             
             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
+                tokens.add(new ValueReferencePtg()); //TODO we need to pass in Name 
+somewhere
             }else {
                 //handle after named range is integrated!!
             }
@@ -277,10 +284,10 @@
     private void Factor() {
         if (Look == '(' ) {
             Match('(');
-            operationsList.add(new ParenthesisPtg());
+            //tokens.add(new ParenthesisPtg());
             Expression();
             Match(')');
-            operationsList.add(new ParenthesisPtg());
+            //tokens.add(new ParenthesisPtg());
             return;
         } else if (IsAlpha(Look)){
             Ident();
@@ -288,7 +295,7 @@
             //EmitLn("MOVE #" + GetNum() + ",D0");
             IntPtg p = new IntPtg();
             p.setValue(Short.parseShort(GetNum()));
-            operandsList.add(p);
+            tokens.add(p);
         }
     }
 
@@ -299,7 +306,7 @@
     private void Multiply(){
         Match('*');
         Factor();
-        operationsList.add(new MultiplyPtg());
+        tokens.add(new MultiplyPtg());
         //EmitLn("MULS (SP)+,D0");
     }
     
@@ -310,7 +317,7 @@
     private void Divide() {
         Match('/');
         Factor();
-        operationsList.add(new DividePtg());
+        tokens.add(new DividePtg());
         //EmitLn("MOVE (SP)+,D1");
         //EmitLn("EXS.L D0");
         //EmitLn("DIVS D1,D0");
@@ -338,7 +345,7 @@
         Match('+');
         Term();
         //EmitLn("ADD (SP)+,D0");
-        operationsList.add(new AddPtg());
+        tokens.add(new AddPtg());
     }
     
     
@@ -348,7 +355,7 @@
     private void Subtract() {
         Match('-');
         Term();
-        operationsList.add(new SubtractPtg());
+        tokens.add(new SubtractPtg());
         //EmitLn("SUB (SP)+,D0");
         //EmitLn("NEG D0");
     }
@@ -364,9 +371,11 @@
             Term();
         }
         while (IsAddop(Look)) {
-            EmitLn("MOVE D0,-(SP)");
+           // EmitLn("MOVE D0,-(SP)");
             if ( Look == '+' )  Add();
             if (Look == '-') Subtract();
+            // if (Look == '*') Multiply();
+           // if (Look == '/') Divide();
         }
     }
     
@@ -397,39 +406,20 @@
         Init();
         Expression();
         //now tokenisation is done .. convert to RPN!!
-        tokenToRPN();
+         /**String s = "";
+           for (int i=0;i<tokens.size();i++) {
+            s=s+ ( (Ptg)tokens.get(i)).toFormulaString();
+            s=s+" ";
+        } **/
+        //System.out.println("Tokens are : " + s);
+        //result = ptgsToRpn(tokens);
     }
     
-    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());
+           for (int i=0;i<tokens.size();i++) {
+            buf.append( ( (Ptg)tokens.get(i)).toFormulaString());
             buf.append(' ');
         } 
         return buf.toString();
Index: MultiplyPtg.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/MultiplyPtg.java,v

retrieving revision 1.1.1.1
diff -u -r1.1.1.1 MultiplyPtg.java
--- MultiplyPtg.java    31 Jan 2002 02:23:44 -0000      1.1.1.1
+++ MultiplyPtg.java    21 Apr 2002 20:41:09 -0000
@@ -118,4 +118,11 @@
         buffer.append(operands[ 1 ].toFormulaString());
         return buffer.toString();
     }
+     public int getPrecedence() {
+        return 4;
+    }
+    
+    public int getStringLength() {
+        return 1;
+    }
 }
Index: OperationPtg.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/OperationPtg.java,v

retrieving revision 1.1.1.1
diff -u -r1.1.1.1 OperationPtg.java
--- OperationPtg.java   31 Jan 2002 02:23:44 -0000      1.1.1.1
+++ OperationPtg.java   21 Apr 2002 20:41:09 -0000
@@ -76,4 +76,6 @@
     public int getNumberOfOperands();
 
     public String toFormulaString(Ptg [] operands);
+    
+    public int getPrecedence();
 }
Index: PowerPtg.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/PowerPtg.java,v

retrieving revision 1.1.1.1
diff -u -r1.1.1.1 PowerPtg.java
--- PowerPtg.java       31 Jan 2002 02:23:44 -0000      1.1.1.1
+++ PowerPtg.java       21 Apr 2002 20:41:10 -0000
@@ -108,6 +108,10 @@
     {
         return "^";
     }
+    
+    public int getPrecedence() {
+        return 3;
+    }
 
     public String toFormulaString(Ptg [] operands)
     {
Index: Ptg.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/Ptg.java,v
retrieving revision 1.2
diff -u -r1.2 Ptg.java
--- Ptg.java    18 Apr 2002 12:00:53 -0000      1.2
+++ Ptg.java    21 Apr 2002 20:41:11 -0000
@@ -77,6 +77,11 @@
     {
     }
     
+    /** return Ptgs in Reverse polish notation order
+     * @return Ptg[]  array of ptgs in rpn order
+     * @param formula  the formula string
+     * @param offset   the offset ??
+     */
     public static Ptg[] parse(String formula, int offset) {
         List ptgs = new ArrayList();
         
@@ -86,8 +91,56 @@
             ptgs.add(ptg);
         }
         
-        Ptg[] retval = new Ptg[ptgs.size()];
-        retval = (Ptg[])ptgs.toArray(retval);
+        List rpnPtgs = ptgsToRpn(ptgs);
+        Ptg[] retval = new Ptg[rpnPtgs.size()];
+        retval = (Ptg[])rpnPtgs.toArray(retval);
+        return retval;
+    }
+    
+    /** convert infix order ptg list to rpn order ptg list
+     * @return List ptgs in RPN order
+     * @param infixPtgs List of ptgs in infix order
+     */
+    public static List ptgsToRpn(List infixPtgs) {
+        java.util.Stack operands = new java.util.Stack();
+        java.util.List retval = new java.util.Stack();
+        
+        java.util.ListIterator i = infixPtgs.listIterator();
+        Object p;
+        OperationPtg o ;
+        boolean weHaveABracket = false;
+        while (i.hasNext()) {
+            p=i.next();
+            if (p instanceof OperationPtg) {
+                if (p instanceof ParenthesisPtg) {
+                    if (!weHaveABracket) {
+                        operands.push(p);
+                        weHaveABracket = true;
+                    } else {
+                        o = (OperationPtg) operands.pop();
+                        while (!(o instanceof ParenthesisPtg)) { 
+                            retval.add(o);
+                        }
+                        weHaveABracket = false;
+                    }
+                } else {
+                    
+                    while  (!operands.isEmpty() && ((OperationPtg) 
+operands.peek()).getPrecedence() >= ((OperationPtg) p).getPrecedence() ) { //TODO 
+handle ^ since it is right associative
+                        retval.add(operands.pop());
+                    }
+                    operands.push(p);
+                }
+            } else {
+                retval.add(p);
+            }
+        }
+        while (!operands.isEmpty()) {
+            if (operands.peek() instanceof ParenthesisPtg ){
+                //throw some error
+            } else {
+                retval.add(operands.pop());
+            }   
+        }
         return retval;
     }
     
@@ -96,6 +149,7 @@
         for (int k =0; k < ptgs.length; k++) {
             Ptg ptg = ptgs[k];
             res.append(ptg.toFormulaString());
+            res.append(' ');
         }
         return res.toString();
     }
Index: SubtractPtg.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/SubtractPtg.java,v

retrieving revision 1.1.1.1
diff -u -r1.1.1.1 SubtractPtg.java
--- SubtractPtg.java    31 Jan 2002 02:23:44 -0000      1.1.1.1
+++ SubtractPtg.java    21 Apr 2002 20:41:12 -0000
@@ -118,4 +118,11 @@
         buffer.append(operands[ 1 ].toFormulaString());
         return buffer.toString();
     }
+     public int getPrecedence() {
+        return 5;
+    }
+    
+    public int getStringLength() {
+        return 1;
+    }
 }

Reply via email to