ETA of my commit....tonight.  I'm looking at all you send.   I'll 
probably devote even more attention to it this weekend.

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');
>    }
>    
>} 
>



Reply via email to