Ejemplo n.º 1
0
        private bool DoRPN(TParsedTokenListBuilder TokenBuilder, TNameRecordList Names, byte[] RPN, int atPos, int afPos, ref bool HasSubtotal, ref bool HasAggregate)
        {
            int tPos     = atPos;
            int fPos     = afPos;
            int ArrayPos = fPos;

            TTokenOffset TokenOffset = new TTokenOffset();

            while (tPos < fPos)
            {
                TokenOffset.Add(tPos, TokenBuilder.Count);
                byte RealToken = RPN[tPos];
                ptg  BaseToken = TBaseParsedToken.CalcBaseToken((ptg)RealToken);
                TUnsupportedFormulaErrorType ErrType = TUnsupportedFormulaErrorType.FormulaTooComplex;
                string ErrName = null;
                if (!Evaluate(TokenBuilder, TokenOffset, Names, BaseToken, (ptg)RealToken, RPN, ref tPos, ref ArrayPos, ref ErrType, ref ErrName, ref HasSubtotal, ref HasAggregate))
                {
                    TokenBuilder.Clear();
                    return(false);
                }
                tPos++;
            }                                          //while

            TokenOffset.Add(tPos, TokenBuilder.Count); //eof

            FixGotosAndMemTokens(TokenBuilder, TokenOffset);
            return(true);
        }
Ejemplo n.º 2
0
        private void FixGotosAndMemTokens(TParsedTokenListBuilder TokenBuilder, TTokenOffset TokenOffset)
        {
            for (int i = TokenBuilder.Count - 1; i >= 0; i--)
            {
                TAttrGotoToken tk = TokenBuilder[i] as TAttrGotoToken;
                if (tk != null)
                {
                    tk.PositionOfNextPtg = TokenOffset[tk.PositionOfNextPtg];
                    continue;
                }

                TAttrOptChooseToken ochoose = TokenBuilder[i] as TAttrOptChooseToken;
                if (ochoose != null)
                {
                    for (int z = 0; z < ochoose.PositionOfNextPtg.Length; z++)
                    {
                        ochoose.PositionOfNextPtg[z] = TokenOffset[ochoose.PositionOfNextPtg[z]];
                    }
                    continue;
                }

                TSimpleMemToken mem = TokenBuilder[i] as TSimpleMemToken;
                if (mem != null)
                {
                    mem.PositionOfNextPtg = TokenOffset[mem.PositionOfNextPtg];
                }
            }
        }
Ejemplo n.º 3
0
        public virtual void Parse()
        {
            LastRefOp          = -1;
            FHasErrors         = false;
            FParsedDataBuilder = new TParsedTokenListBuilder();
            try
            {
                Go();
                FParsedData            = FParsedDataBuilder.ToParsedTokenList();
                FParsedData.TextLenght = FormulaText.Length;
            }
            finally
            {
                FParsedDataBuilder = null;
            }

            //Try to decode what we encoded
            //something like "= >" will be encoded nicely, but will crash when decoded

            /*try
             * {
             *      FParsedData.ResetPositionToLast();
             *      FParsedData.Flush();
             *      if (!FParsedData.Bof())FlxMessages.ThrowException(FlxErr.ErrFormulaInvalid, FormulaText);
             * }
             * catch (Exception)
             * {
             *      FlxMessages.ThrowException(FlxErr.ErrFormulaInvalid,FormulaText);
             * }*/
        }
Ejemplo n.º 4
0
        protected static void AddParsedRefN(TParsedTokenListBuilder TokenBuilder, ptg aId, int Rw1, int grBit1)
        {
            bool RowAbs; bool ColAbs; int Row; int Col;

            GetRelativeRowAndCol(Rw1, grBit1, out RowAbs, out ColAbs, out Row, out Col);
            Push(TokenBuilder, new TRefNToken(aId, Row, Col, RowAbs, ColAbs, true));
        }
Ejemplo n.º 5
0
 private void AddParsedTable(TParsedTokenListBuilder TokenBuilder, int Row, int Col)
 {
     if (IsFmlaObject)
     {
         Push(TokenBuilder, new TTableObjToken(Row, Col));
     }
     else
     {
         Push(TokenBuilder, new TTableToken(Row, Col));
     }
 }
Ejemplo n.º 6
0
        protected static void AddParsedAreaN(TParsedTokenListBuilder TokenBuilder, ptg aId, int Rw1, int Rw2, int grBit1, int grBit2)
        {
            bool RowAbs1; bool ColAbs1; int Row1; int Col1;

            GetRelativeRowAndCol(Rw1, grBit1, out RowAbs1, out ColAbs1, out Row1, out Col1);
            bool RowAbs2; bool ColAbs2; int Row2; int Col2;

            GetRelativeRowAndCol(Rw2, grBit2, out RowAbs2, out ColAbs2, out Row2, out Col2);

            Push(TokenBuilder, new TAreaNToken(aId, Row1, Col1, RowAbs1, ColAbs1, Row2, Col2, RowAbs2, ColAbs2, true));
        }
Ejemplo n.º 7
0
        protected override void AddParsedOp(TOperator op)
        {
            TBaseParsedToken OpToken = TParsedTokenListBuilder.GetParsedOp(op);

            if (OpToken is TUnsupportedToken)
            {
                DoError(FlxErr.ErrFormulaInvalid, 2);
            }
            else
            {
                Push(OpToken);
            }
        }
Ejemplo n.º 8
0
        protected static void AddParsedSep(TParsedTokenListBuilder TokenBuilder, ptg b)
        {
            switch (b)
            {
            case ptg.Isect: Push(TokenBuilder, TISectToken.Instance); break;

            case ptg.Union: Push(TokenBuilder, TUnionToken.Instance); break;

            case ptg.Range: Push(TokenBuilder, TRangeToken.Instance); break;

            default: Push(TokenBuilder, new TUnsupportedToken(2, b)); break;
            }
        }
Ejemplo n.º 9
0
        public TParsedTokenList ParseRPN(TNameRecordList Names, int aRow, int aCol, byte[] Data, int atPos, int fmlaLen, bool aRelative3dRanges, out bool HasSubtotal, out bool HasAggregate, bool aIsFmlaObject)
        {
            HasSubtotal      = false;
            HasAggregate     = false;
            Relative3dRanges = aRelative3dRanges;
            IsFmlaObject     = aIsFmlaObject;
            TParsedTokenListBuilder TokenBuilder = new TParsedTokenListBuilder();

            if (!DoRPN(TokenBuilder, Names, Data, atPos, atPos + fmlaLen, ref HasSubtotal, ref HasAggregate))
            {
                XlsMessages.ThrowException(XlsErr.ErrBadFormula, aRow + 1, aCol + 1, 0);
            }
            return(TokenBuilder.ToParsedTokenList());
        }
Ejemplo n.º 10
0
 private void AddParsed3dRef(TParsedTokenListBuilder TokenBuilder, ptg RealToken, int ExternSheet, int Rw1, int grBit1)
 {
     if (Relative3dRanges)
     {
         bool RowAbs1; bool ColAbs1; int Row1; int Col1;
         GetRelativeRowAndCol(Rw1, grBit1, out RowAbs1, out ColAbs1, out Row1, out Col1);
         Push(TokenBuilder, new TRef3dNToken(RealToken, ExternSheet, Row1, Col1, RowAbs1, ColAbs1, true));
     }
     else
     {
         Push(TokenBuilder, new TRef3dToken(RealToken, ExternSheet, Biff8Utils.ExpandBiff8Row(Rw1),
                                            Biff8Utils.ExpandBiff8Col(grBit1 & ColMask), (grBit1 & 0x8000) == 0, (grBit1 & 0x4000) == 0));
     }
 }
Ejemplo n.º 11
0
        private void CheckFutureFunction(TParsedTokenListBuilder TokenBuilder, ref int np, TNameRecordList Names, ref TCellFunctionData fd2, TTokenOffset TokenOffset, ref bool HasAggregate)
        {
            //We need to recursively read parameters in back order to find out the name, which is stored as far as possible from the function :(
            TParsedTokenList ParsedList = TokenBuilder.ToParsedTokenList();

            ParsedList.ResetPositionToLast();
            for (int i = 0; i < np; i++) //np is +1. But we will move below the name, then inc 1, so we know there isn't a "neutral" token like parent or memarea, intead of the real thing.
            {
                ParsedList.Flush();
            }

            ParsedList.MoveBack();
            TNameToken bp = ParsedList.ForwardPop() as TNameToken;

            if (bp is TNameXToken)
            {
                return;                    //This name isn't an internal 2007 name.
            }
            if (bp == null)
            {
                return;
            }
            if (bp.NameIndex <= 0 || bp.NameIndex > Names.Count)
            {
                return;
            }
            string FunctionName = Names[bp.NameIndex - 1].Name;

            if (FunctionName.StartsWith("_xlfn.", StringComparison.InvariantCultureIgnoreCase))
            {
                TCellFunctionData fn = TXlsFunction.GetData(FunctionName.Substring("_xlfn.".Length));
                if (fn != null)
                {
                    if (fn.Index == (int)TFutureFunctions.Aggregate)
                    {
                        HasAggregate = true;
                    }

                    fd2 = fn;
                    int tPos = ParsedList.SavePosition();
                    TokenBuilder.RemoveAt(tPos);
                    TokenOffset.RemoveToken(tPos);
                    np--;
                }
            }
        }
Ejemplo n.º 12
0
        protected override void AddParsedFunction(TCellFunctionData Func, byte ArgCount)
        {
            ptg FmlaPtg;

            if (Func.MinArgCount != Func.MaxArgCount || Func.FutureInXls)
            {
                FmlaPtg = GetRealPtg(ptg.FuncVar, Func.ReturnType);
            }
            else
            {
                FmlaPtg = GetRealPtg(ptg.Func, Func.ReturnType);
            }

            TBaseParsedToken FmlaToken = TParsedTokenListBuilder.GetParsedFormula(FmlaPtg, Func, ArgCount);

            Push(FmlaToken);
        }
Ejemplo n.º 13
0
        private bool ProcessAttr(TParsedTokenListBuilder TokenBuilder, byte[] RPN, int tPos, ref int AttrLen)
        {
            AttrLen = 3;

            if ((RPN[tPos] & 0x10) == 0x10)
            { //optimized sum
                Push(TokenBuilder, TAttrSumToken.Instance);
                return(true);
            }

            if ((RPN[tPos] & 0x40) == 0x40)  //Spaces. As we can have volatile spaces, this should go before the check for volatile.
            {
                Push(TokenBuilder, new TAttrSpaceToken((FormulaAttr)RPN[tPos + 1], RPN[tPos + 2], (RPN[tPos] & 0x1) == 0x1));
                return(true);
            }

            if ((RPN[tPos] & 0x1) == 0x1) //volatile
            {
                Push(TokenBuilder, TAttrVolatileToken.Instance);
                return(true);
            }


            if ((RPN[tPos] & 0x2) == 0x2) //Optimized if
            {
                //It works the same by ignoring this and the optif tokens, but it is slower.
                //On a normal if you have:  [cond], [trueexpr], [falseexpr], [if]
                //so, it doesn't matter condition is false or true, both truexpr and falsexpr will be evaluated.
                //On an optimized if you have: [Cond], [AttrIf], [true], [Goto],[false], [Goto], [if]
                //                                                          |---------------|--------->
                //                                        |-------------------->
                //
                //So, you evaluate Cond. Next token is AttrIf, it Cond is true if will continue, if false jump before [false]
                //Now evaluate true or false, and the goto goes after if.

                Push(TokenBuilder, new TAttrOptIfToken(tPos + AttrLen + BitOps.GetWord(RPN, tPos + 1)));//temporarily store the stream offset in the token, it will be fixed by FixTokens
                return(true);
            }

            if ((RPN[tPos] & 0x04) == 0x04)
            {
                //This works like the optimized if.
                //For example:
                // = Choose(Index,3/0,4)
                //would be parsed as:
                // Index, AttrChoose, 3, 0, /, Goto, 4, Goto, Choose.
                //
                // Then we can get from the index the direct position of the token, and after it there is a goto to the end.

                AttrLen += (BitOps.GetWord(RPN, tPos + 1) + 1) * 2;
                Push(TokenBuilder, new TAttrOptChooseToken(GetOptChoose(RPN, tPos + 1, tPos + 3))); //distance goes from start of jump table.
                return(true);
            }

            if ((RPN[tPos] & 0x8) == 0x8 || RPN[tPos] == 0x0) //Goto.  0x0 is not documented, but might happen and means goto.
            {
                //Goto can't really be implemented with our engine.
                //The Excel engine has a stack and travels from left to right. Say you have the RPN 5,7,+:
                //Excel would push 5 and 7 to the stack, then the "+" would pop those values and push 12.
                //We use a recursive approach where the stack is implicit, so we start by "+", and it recusively gets
                //its 2 arguments. Bt if we add a jmp before the 5, we are never going to see it this way. Excel would.
                //It doesn't really matter since gotos are optimizations and can be ignored.

                Push(TokenBuilder, new TAttrGotoToken(1 + tPos + AttrLen + BitOps.GetWord(RPN, tPos + 1))); //temporarily store the stream offset in the token, it will be fixed by FixTokens
                return(true);
            }

            //return false;
            return(true);
        }
Ejemplo n.º 14
0
        private bool Evaluate(TParsedTokenListBuilder TokenBuilder, TTokenOffset TokenOffset, TNameRecordList Names, ptg BaseToken, ptg RealToken,
                              byte[] RPN, ref int tPos, ref int ArrayPos, ref TUnsupportedFormulaErrorType ErrType, ref string ErrName, ref bool HasSubtotal, ref bool HasAggregate)
        {
            switch (BaseToken)
            {
            case ptg.Exp:
                AddParsedExp(TokenBuilder, BitOps.GetWord(RPN, tPos + 1), BitOps.GetWord(RPN, tPos + 3));
                tPos += 4;
                break;

            case ptg.Tbl:
                AddParsedTable(TokenBuilder, BitOps.GetWord(RPN, tPos + 1), BitOps.GetWord(RPN, tPos + 3));
                tPos += 4;
                break;

            case ptg.Add:
            case ptg.Sub:
            case ptg.Mul:
            case ptg.Div:
            case ptg.Power:
            case ptg.Concat:
            case ptg.LT:
            case ptg.LE:
            case ptg.EQ:
            case ptg.GE:
            case ptg.GT:
            case ptg.NE:
            case ptg.Uminus:
            case ptg.Percent:
            case ptg.Uplus:
                AddParsedOp(TokenBuilder, (TOperator)BaseToken); break;

            case ptg.MissArg: AddMissingArg(TokenBuilder); break;


            case ptg.Isect: AddParsedSep(TokenBuilder, BaseToken); break;

            case ptg.Union: AddParsedSep(TokenBuilder, BaseToken); break;

            case ptg.Range: AddParsedSep(TokenBuilder, BaseToken); break;

            case ptg.Paren: Push(TokenBuilder, TParenToken.Instance); break;

            case ptg.Str:
                long   sl     = 0;
                string Result = null;
                StrOps.GetSimpleString(false, RPN, tPos + 1, false, 0, ref Result, ref sl);
                AddParsed(TokenBuilder, Result);
                tPos += (int)sl;
                break;

            case ptg.Attr: int AttrLen = 0; if (!ProcessAttr(TokenBuilder, RPN, tPos + 1, ref AttrLen))
                {
                    return(false);
                }
                tPos += AttrLen; break;

            case ptg.Sheet:  return(false);

            case ptg.EndSheet:  return(false);

            case ptg.Err: AddParsed(TokenBuilder, (TFlxFormulaErrorValue)RPN[tPos + 1]); tPos++; break;

            case ptg.Bool: AddParsed(TokenBuilder, RPN[tPos + 1] == 1); tPos++; break;

            case ptg.Int: AddParsed16(TokenBuilder, BitOps.GetWord(RPN, tPos + 1)); tPos += 2; break;

            case ptg.Num: AddParsed(TokenBuilder, BitConverter.ToDouble(RPN, tPos + 1)); tPos += 8; break;

            case ptg.Array: Push(TokenBuilder, GetArrayDataToken(RealToken, RPN, ref ArrayPos)); tPos += 7; break;

            case ptg.Func:
                bool Result1;
                int  index           = BitOps.GetWord(RPN, tPos + 1);
                TCellFunctionData fd = TXlsFunction.GetData(index, out Result1);
                if (!Result1)
                {
                    return(false);
                }

                Debug.Assert(fd.MinArgCount == fd.MaxArgCount, "On a fixed formula the min count of arguments should be the same as the max");
                AddParsedFormula(TokenBuilder, RealToken, fd, (byte)fd.MinArgCount);
                tPos += 2;
                break;

            case ptg.FuncVar:
                bool Result2;
                int  index2           = BitOps.GetWord(RPN, tPos + 2);
                TCellFunctionData fd2 = TXlsFunction.GetData(index2, out Result2);
                if (!Result2)
                {
                    return(false);
                }

                if (fd2.Index == 344)                       // SubTotal
                {
                    HasSubtotal = true;
                }

                int np = RPN[tPos + 1] & 0x7F;

                if (fd2.Index == 255)
                {
                    CheckFutureFunction(TokenBuilder, ref np, Names, ref fd2, TokenOffset, ref HasAggregate);
                }


                AddParsedFormula(TokenBuilder, RealToken, fd2, (byte)np);

                tPos += 3;
                break;

            case ptg.Name:
                Push(TokenBuilder, new TNameToken(RealToken, BitOps.GetWord(RPN, tPos + 1)));
                tPos += 4;
                break;

            case ptg.NameX:
                Push(TokenBuilder, new TNameXToken(RealToken, BitOps.GetWord(RPN, tPos + 1), BitOps.GetWord(RPN, tPos + 3)));
                tPos += 6;
                break;

            case ptg.RefErr:
            case ptg.Ref:
                AddParsedRef(TokenBuilder, RealToken, BitOps.GetWord(RPN, tPos + 1), BitOps.GetWord(RPN, tPos + 2 + 1)); tPos += 4;
                break;

            case ptg.RefN:
                AddParsedRefN(TokenBuilder, RealToken, BitOps.GetWord(RPN, tPos + 1), BitOps.GetWord(RPN, tPos + 2 + 1)); tPos += 4;
                break;

            case ptg.AreaErr:
            case ptg.Area:
                AddParsedArea(TokenBuilder, RealToken, BitOps.GetWord(RPN, tPos + 1), BitOps.GetWord(RPN, tPos + 2 + 1), BitOps.GetWord(RPN, tPos + 4 + 1), BitOps.GetWord(RPN, tPos + 6 + 1)); tPos += 8;
                break;

            case ptg.AreaN:
                AddParsedAreaN(TokenBuilder, RealToken, BitOps.GetWord(RPN, tPos + 1), BitOps.GetWord(RPN, tPos + 2 + 1), BitOps.GetWord(RPN, tPos + 4 + 1), BitOps.GetWord(RPN, tPos + 6 + 1)); tPos += 8;
                break;

            case ptg.MemArea:
            {
                int ArrayLen;
                Push(TokenBuilder, new TMemAreaToken(RealToken, GetMemControl(RPN, ArrayPos, out ArrayLen), tPos + 1 + 6 + BitOps.GetWord(RPN, tPos + 1 + 4)));
                ArrayPos += ArrayLen; tPos += 6;
                break;                         //this is an optimization, but we don't need it.
            }

            case ptg.MemErr:
            {
                Push(TokenBuilder, new TMemErrToken(RealToken, (TFlxFormulaErrorValue)RPN[tPos + 1], tPos + 1 + 6 + BitOps.GetWord(RPN, tPos + 1 + 4)));
                tPos += 6;
                break;                         //this is an optimization, but we don't need it.
            }

            case ptg.MemNoMem:
            {
                Push(TokenBuilder, new TMemNoMemToken(RealToken, tPos + 1 + 6 + BitOps.GetWord(RPN, tPos + 1 + 4)));
                tPos += 6;
                break;                         //this is an optimization, but we don't need it.
            }

            case ptg.MemFunc:
            {
                Push(TokenBuilder, new TMemFuncToken(RealToken, tPos + 1 + 2 + BitOps.GetWord(RPN, tPos + 1)));
                tPos += 2;
                break;                         //this is an optimization, but we don't need it.
            }

            case ptg.MemAreaN:
            {
                Push(TokenBuilder, new TMemAreaNToken(RealToken, tPos + 1 + 2 + BitOps.GetWord(RPN, tPos + 1)));
                tPos += 2;
                break;                         //this is an optimization, but we don't need it.
            }

            case ptg.MemNoMemN:
            {
                Push(TokenBuilder, new TMemNoMemNToken(RealToken, tPos + 1 + 2 + BitOps.GetWord(RPN, tPos + 1)));
                tPos += 2;
                break;                         //this is an optimization, but we don't need it.
            }


            case ptg.Ref3dErr:
            case ptg.Ref3d:
            {
                int grBit1      = BitOps.GetWord(RPN, tPos + 4 + 1);
                int ExternSheet = BitOps.GetWord(RPN, tPos + 1);
                int Row1        = BitOps.GetWord(RPN, tPos + 2 + 1);
                AddParsed3dRef(TokenBuilder, RealToken, ExternSheet, Row1, grBit1);

                tPos += 6;
                break;
            }

            case ptg.Area3dErr:
            case ptg.Area3d:
            {
                int ExternSheet = BitOps.GetWord(RPN, tPos + 1);
                int Row1        = BitOps.GetWord(RPN, tPos + 2 + 1);
                int Row2        = BitOps.GetWord(RPN, tPos + 4 + 1);
                int grBit1      = BitOps.GetWord(RPN, tPos + 6 + 1);
                int grBit2      = BitOps.GetWord(RPN, tPos + 8 + 1);
                AddParsed3dArea(TokenBuilder, RealToken, ExternSheet, Row1, Row2, grBit1, grBit2);

                tPos += 10;
                break;
            }

            default: return(false);
            }
            return(true);
        }
Ejemplo n.º 15
0
 protected static void AddParsed16(TParsedTokenListBuilder TokenBuilder, int t)
 {
     Push(TokenBuilder, new TIntDataToken(t));
 }
Ejemplo n.º 16
0
 private static void AddParsedExp(TParsedTokenListBuilder TokenBuilder, int Row, int Col)
 {
     Push(TokenBuilder, new TExp_Token(Row, Col));
 }
Ejemplo n.º 17
0
 protected static void AddParsed(TParsedTokenListBuilder TokenBuilder, double d)
 {
     Push(TokenBuilder, new TNumDataToken(d));
 }
Ejemplo n.º 18
0
 protected static void AddParsed(TParsedTokenListBuilder TokenBuilder, TFlxFormulaErrorValue err)
 {
     Push(TokenBuilder, new TErrDataToken(err));
 }
Ejemplo n.º 19
0
 protected static void AddParsedOp(TParsedTokenListBuilder TokenBuilder, TOperator op)
 {
     Push(TokenBuilder, TParsedTokenListBuilder.GetParsedOp(op));
 }
Ejemplo n.º 20
0
 protected static void AddParsedArea(TParsedTokenListBuilder TokenBuilder, ptg aId, int Rw1, int Rw2, int grBit1, int grBit2)
 {
     Push(TokenBuilder, new TAreaToken(aId, Biff8Utils.ExpandBiff8Row(Rw1), Biff8Utils.ExpandBiff8Col(grBit1 & ColMask), (grBit1 & 0x8000) == 0, (grBit1 & 0x4000) == 0,
                                       Biff8Utils.ExpandBiff8Row(Rw2), Biff8Utils.ExpandBiff8Col(grBit2 & ColMask), (grBit2 & 0x8000) == 0, (grBit2 & 0x4000) == 0));
 }
Ejemplo n.º 21
0
 protected static void AddParsed(TParsedTokenListBuilder TokenBuilder, string s)
 {
     Push(TokenBuilder, new TStrDataToken(s, null, false));
 }
Ejemplo n.º 22
0
 protected static void AddMissingArg(TParsedTokenListBuilder TokenBuilder)
 {
     Push(TokenBuilder, TMissingArgDataToken.Instance);
 }
Ejemplo n.º 23
0
 protected static void Push(TParsedTokenListBuilder TokenBuilder, TBaseParsedToken obj)
 {
     TokenBuilder.Add(obj);
 }
Ejemplo n.º 24
0
        protected static void AddParsedFormula(TParsedTokenListBuilder TokenBuilder, ptg FmlaPtg, TCellFunctionData Func, byte ArgCount)
        {
            TBaseParsedToken FmlaToken = TParsedTokenListBuilder.GetParsedFormula(FmlaPtg, Func, ArgCount);

            Push(TokenBuilder, FmlaToken);             //Always push unsupported.
        }
Ejemplo n.º 25
0
 protected static void AddParsed(TParsedTokenListBuilder TokenBuilder, bool b)
 {
     Push(TokenBuilder, new TBoolDataToken(b));
 }