So lets go ahead and now you can sync up (send your patches).  I put my
code in.  Its not very useful just me screwing around, but I about have
enough idea what to do now.

-andy

On Mon, 2002-04-01 at 23:52, Avik Sengupta wrote:
> Attached is YET another version of formula parser, now with a static method 
> that can convert a RPN order array of Ptgs into human readable infix order 
> formula string. 
> 
> This change depends on changes to many ptg files, so i will not even attempt to 
> send accross a full set to the list. After I merge my stuff with what andy has 
> done, i will send a proper patch. Till then you will have to live with these 
> bits and pieces :(
> 
> Cheers
> -
> Avik
> 
> 
> ----
> 

> 
> /* ====================================================================
>  * 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 [EMAIL PROTECTED]
>  *
>  * 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 
>  *
>  * @author Avik Sengupta <avik AT Avik Sengupta DOT com>
>  *
>  * 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 List tokens = new java.util.Stack();
>     //private Stack tokens = new java.util.Stack();
>     private List result = new ArrayList();
>     private int numParen;
>     
>     private static char TAB = '\t';
>     private static char CR = '\n';
>     
>    private char Look;              // Lookahead Character 
>     
>     
>     /** create the parser with the string that is to be parsed
>      *    later call the parse() method to return ptg list in rpn order
>      *    then call the getRPNPtg() to retrive the parse results
>      *  This class is recommended only for single threaded use
>      *  The parse and getPRNPtg are internally synchronized for safety, thus
>      *  while it is safe to use in a multithreaded environment, you will get long 
>lock waits.  
>      */
>     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);
>     }
>     
>     
>  
>     /** Recognize a Decimal Digit */
>     private boolean IsDigit(char c) {
>         //System.out.println("Checking digit for"+c);
>         return Character.isDigit(c);
>     }
>     
>     
> 
>     /** Recognize an Alphanumeric */
>     private boolean  IsAlNum(char c) {
>         return  (IsAlpha(c) || IsDigit(c));
>     }
>     
>     
> 
>     /** Recognize an Addop */
>     private boolean IsAddop( char c) {
>         return (c =='+' || c =='-');
>     }
>     
> 
>     /** Recognize White Space */
>     private boolean IsWhite( char c) {
>         return  (c ==' ' || c== TAB);
>     }
>     
>     
> 
>     /** Skip Over Leading White Space */
>     private void SkipWhite() {
>         while (IsWhite(Look)) {
>             GetChar();
>         }
>     }
>     
>     
> 
>     /** Match a Specific Input Character */
>     private void Match(char x) {
>         if (Look != x) {
>             Expected("" + x + "");
>         }else {
>             GetChar();
>             SkipWhite();
>         }
>     }
>     
>     
>     /** Get an Identifier */
>     private String GetName() {
>         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 == '('){
>             //This is a function 
>             Match('(');
>             int numArgs = Arguments(); //Expression() -- add this!
>             Match(')');
>             //this is the end of the function
>             tokens.add(new DummyFunctionPtg(Name,numArgs));
>         } else {
>             //this can be either a cell ref or a named range !!
>             
>             boolean cellRef = true ; //we should probably do it with reg exp??
>             if (cellRef) {
>                 tokens.add(new ValueReferencePtg()); //TODO we need to pass in Name 
>somewhere??
>             }else {
>                 //handle after named range is integrated!!
>             }
>         }
>     }
>     
>     /** get arguments to a function */
>     private int Arguments() {
>         int numArgs = 0;
>         if (Look != ')')  {
>             numArgs++; 
>             Expression();
>         }
>         while (Look == ',') {
>             Match(',');
>             Expression();
>             numArgs++;
>         }
>         return numArgs;
>     }
> 
>    /** Parse and Translate a Math Factor  */
>     private void Factor() {
>         if (Look == '(' ) {
>             Match('(');
>             //tokens.add(new ParenthesisPtg());
>             Expression();
>             Match(')');
>             //tokens.add(new ParenthesisPtg());
>             return;
>         } else if (IsAlpha(Look)){
>             Ident();
>         }else{
>             //EmitLn("MOVE #" + GetNum() + ",D0");
>             IntPtg p = new IntPtg();
>             p.setValue(Short.parseShort(GetNum()));
>             tokens.add(p);
>         }
>     }
> 
>     
>     /** Recognize and Translate a Multiply */
>     private void Multiply(){
>         Match('*');
>         Factor();
>         tokens.add(new MultiplyPtg());
>         //EmitLn("MULS (SP)+,D0");
>     }
>     
>     
>     /** Recognize and Translate a Divide */
>     private void Divide() {
>         Match('/');
>         Factor();
>         tokens.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();
>         tokens.add(new AddPtg());
>     }
>     
>     
>     /** Recognize and Translate a Subtract */
>     private void Subtract() {
>         Match('-');
>         Term();
>         tokens.add(new SubtractPtg());
>     }
>     
>     
>     /** Parse and Translate an Expression */
>     private void Expression() {
>         if (IsAddop(Look)) {
>             EmitLn("CLR D0");  //unaryAdd ptg???
>         } else {
>             Term();
>         }
>         while (IsAddop(Look)) {
>             if ( Look == '+' )  Add();
>             if (Look == '-') Subtract();
>             // if (Look == '*') Multiply();
>            // if (Look == '/') Divide();
>         }
>     }
>     
>     
>     //{--------------------------------------------------------------}
>     //{ Parse and Translate an Assignment Statement }
>     /**
> procedure Assignment;
> var Name: string[8];
> begin
>    Name := GetName;
>    Match('=');
>    Expression;
> 
> end;
>      **/
>     
>  
>     /** Initialize */
>     
>     private void  Init() {
>         GetChar();
>         SkipWhite();
>     }
>     
>     /** API call to execute the parsing of the formula
>      *
>      */
>     public void parse() {
>         synchronized (tokens) {
>             Init();
>             Expression();
>         }
>     }
>     
>     /** API call to retrive the array of Ptgs created as 
>      * 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);
>        }
>     }
>     
>     /** Static method to convert an array of Ptgs in RPN order 
>      *  to a human readable string format in infix mode
>      *  TODO - extra brackets might appear, but string will be semantically correct. 
>      */
>     public static String toFormulaString(Ptg[] ptgs) {
>         java.util.Stack stack = new java.util.Stack();
>         int numPtgs = ptgs.length;
>         OperationPtg o;
>         int numOperands;
>         String[] operands;
>         for (int i=0;i<numPtgs;i++) {
>             if (ptgs[i] instanceof OperationPtg) {
>                 o = (OperationPtg) ptgs[i];
>                 numOperands = o.getNumberOfOperands();
>                 operands = new String[numOperands];
>                 for (int j=0;j<numOperands;j++) {
>                     operands[numOperands-j-1] = (String) stack.pop(); //TODO: catch 
>stack underflow and throw parse exception. 
>                     
>                 }  
>                 String result = o.toFormulaString(operands);
>                 if (! (o instanceof DummyFunctionPtg) ) result = "("+result+")" ;
>                 stack.push(result);
>             } else {
>                 stack.push(ptgs[i].toFormulaString());
>             }
>         }
>         return (String) stack.pop(); //TODO: catch stack underflow and throw parse 
>exception. 
>     }
>    
>     public String toString() {
>         StringBuffer buf = new StringBuffer();
>            for (int i=0;i<tokens.size();i++) {
>             buf.append( ( (Ptg)tokens.get(i)).toFormulaString());
>             buf.append(' ');
>         } 
>         return buf.toString();
>     }
>     
>     
>     /** Main Program for testing*/
>     public static void main(String[] argv) {
>         FormulaParser fp = new FormulaParser(argv[0]+";");
>         System.out.println("\nFormula is: ");
>         fp.parse();
>         System.out.println("RPN Form is: " +fp.toString());
>         
>         System.out.println("Converted Text form is : 
>"+fp.toFormulaString(fp.getRPNPtg()));
>         
>         //If Look <> CR then Expected('NewLine');
>     }
>     
> } 
-- 
http://www.superlinksoftware.com
http://jakarta.apache.org/poi - port of Excel/Word/OLE 2 Compound
Document 
                            format to java
http://developer.java.sun.com/developer/bugParade/bugs/4487555.html 
                        - fix java generics!
The avalanche has already started. It is too late for the pebbles to
vote.
-Ambassador Kosh

Reply via email to