Ejemplo n.º 1
0
 public ParseNode(Ptg token, ParseNode[] children)
 {
     _token = token;
     _children = children;
     _isIf = IsIf(token);
     int tokenCount = 1;
     for (int i = 0; i < children.Length; i++)
     {
         tokenCount += children[i].TokenCount;
     }
     if (_isIf)
     {
         // there will be 2 or 3 extra tAttr Tokens according To whether the false param is present
         tokenCount += children.Length;
     }
     _tokenCount = tokenCount;
 }
        /**
         * Traverses the supplied formula parse tree, calling <c>Ptg.SetClass()</c> for each non-base
         * Token To Set its operand class.
         */
        public void TransformFormula(ParseNode rootNode)
        {
            byte rootNodeOperandClass;
            switch (_formulaType)
            {
                case FormulaType.CELL:
                    rootNodeOperandClass = Ptg.CLASS_VALUE;
                    break;
                case FormulaType.ARRAY:
                    rootNodeOperandClass = Ptg.CLASS_ARRAY;
                    break;
                case FormulaType.NAMEDRANGE:
                case FormulaType.DATAVALIDATION_LIST:
                    rootNodeOperandClass = Ptg.CLASS_REF;
                    break;
                default:
                    throw new Exception("Incomplete code - formula type ("
                            + _formulaType + ") not supported yet");

            }
            TransformNode(rootNode, rootNodeOperandClass, false);
        }
Ejemplo n.º 3
0
        private ParseNode ParseRangeExpression()
        {
            ParseNode result = ParseRangeable();
            bool hasRange = false;
            while (look == ':')
            {
                int pos = pointer;
                GetChar();
                ParseNode nextPart = ParseRangeable();
                // Note - no range simplification here. An expr like "A1:B2:C3:D4:E5" should be
                // grouped into area ref pairs like: "(A1:B2):(C3:D4):E5"
                // Furthermore, Excel doesn't seem to simplify
                // expressions like "Sheet1!A1:Sheet1:B2" into "Sheet1!A1:B2"

                CheckValidRangeOperand("LHS", pos, result);
                CheckValidRangeOperand("RHS", pos, nextPart);

                ParseNode[] children = { result, nextPart, };
                result = new ParseNode(RangePtg.instance, children);
                hasRange = true;
            }
            if (hasRange)
            {
                return AugmentWithMemPtg(result);
            }
            return result;
        }
Ejemplo n.º 4
0
 private ParseNode UnionExpression()
 {
     ParseNode result = ComparisonExpression();
     bool hasUnions = false;
     while (true)
     {
         SkipWhite();
         switch (look)
         {
             case ',':
                 GetChar();
                 hasUnions = true;
                 ParseNode other = ComparisonExpression();
                 result = new ParseNode(UnionPtg.instance, result, other);
                 continue;
         }
         if (hasUnions)
         {
             return AugmentWithMemPtg(result);
         }
         return result;
     }
 }
Ejemplo n.º 5
0
        //{--------------------------------------------------------------}
        //{ Parse and Translate an Assignment Statement }
        /*
    procedure Assignment;
    var Name: string[8];
    begin
       Name := GetName;
       Match('=');
       Expression;

    end;
         **/


        /**
         *  API call To execute the parsing of the formula
         * 
         */
        private void Parse()
        {
            pointer = 0;
            GetChar();
            _rootNode = UnionExpression();

            if (pointer <= formulaLength)
            {
                String msg = "Unused input [" + formulaString.Substring(pointer - 1)
                    + "] after attempting To Parse the formula [" + formulaString + "]";
                throw new FormulaParseException(msg);
            }
        }
Ejemplo n.º 6
0
 /** Parse and Translate an Expression */
 private ParseNode AdditiveExpression()
 {
     ParseNode result = Term();
     while (true)
     {
         SkipWhite();
         Ptg operator1;
         switch (look)
         {
             case '+':
                 Match('+');
                 operator1 = AddPtg.instance;
                 break;
             case '-':
                 Match('-');
                 operator1 = SubtractPtg.instance;
                 break;
             default:
                 return result; // finished with Additive expression
         }
         ParseNode other = Term();
         result = new ParseNode(operator1, result, other);
     }
 }
Ejemplo n.º 7
0
 private ParseNode ConcatExpression()
 {
     ParseNode result = AdditiveExpression();
     while (true)
     {
         SkipWhite();
         if (look != '&')
         {
             break; // finished with concat expression
         }
         Match('&');
         ParseNode other = AdditiveExpression();
         result = new ParseNode(ConcatPtg.instance, result, other);
     }
     return result;
 }
Ejemplo n.º 8
0
        /**
 * @param currentParsePosition used to format a potential error message
 */
        private void CheckValidRangeOperand(String sideName, int currentParsePosition, ParseNode pn)
        {
            if (!IsValidRangeOperand(pn))
            {
                throw new FormulaParseException("The " + sideName
                        + " of the range operator ':' at position "
                        + currentParsePosition + " is not a proper reference.");
            }
        }
Ejemplo n.º 9
0
 private ParseNode PercentFactor()
 {
     ParseNode result = ParseSimpleFactor();
     while (true)
     {
         SkipWhite();
         if (look != '%')
         {
             return result;
         }
         Match('%');
         result = new ParseNode(PercentPtg.instance, result);
     }
 }
Ejemplo n.º 10
0
 /** Parse and Translate a Math Factor  */
 private ParseNode PowerFactor()
 {
     ParseNode result = PercentFactor();
     while (true)
     {
         SkipWhite();
         if (look != '^')
         {
             return result;
         }
         Match('^');
         ParseNode other = PercentFactor();
         result = new ParseNode(PowerPtg.instance, result, other);
     }
 }
Ejemplo n.º 11
0
        /**
         * Generates the variable Function ptg for the formula.
         * 
         * For IF Formulas, Additional PTGs are Added To the Tokens
	 * @param name a {@link NamePtg} or {@link NameXPtg} or <code>null</code>
         * @return Ptg a null is returned if we're in an IF formula, it needs extreme manipulation and is handled in this Function
         */
        private ParseNode GetFunction(String name, Ptg namePtg, ParseNode[] args)
        {

            FunctionMetadata fm = FunctionMetadataRegistry.GetFunctionByName(name.ToUpper());
            int numArgs = args.Length;
            if (fm == null)
            {
                if (namePtg == null)
                {
                    throw new InvalidOperationException("NamePtg must be supplied for external Functions");
                }
                // must be external Function
                ParseNode[] allArgs = new ParseNode[numArgs + 1];
                allArgs[0] = new ParseNode(namePtg);
                System.Array.Copy(args, 0, allArgs, 1, numArgs);
                return new ParseNode(FuncVarPtg.Create(name, (byte)(numArgs + 1)), allArgs);
            }

            if (namePtg != null)
            {
                throw new InvalidOperationException("NamePtg no applicable To internal Functions");
            }
            bool IsVarArgs = !fm.HasFixedArgsLength;
            int funcIx = fm.Index;
		if (funcIx == FunctionMetadataRegistry.FUNCTION_INDEX_SUM && args.Length == 1) {
			// Excel encodes the sum of a single argument as tAttrSum
			// POI does the same for consistency, but this is not critical
			return new ParseNode(AttrPtg.GetSumSingle(), args);
			// The code below would encode tFuncVar(SUM) which seems to do no harm
		}
            ValidateNumArgs(args.Length, fm);

            AbstractFunctionPtg retval;
            if (IsVarArgs)
            {
                retval = FuncVarPtg.Create(name, (byte)numArgs);
            }
            else
            {
                retval = FuncPtg.Create(funcIx);
            }
            return new ParseNode(retval, args);
        }
Ejemplo n.º 12
0
 /**
  * Collects the array of <c>Ptg</c> Tokens for the specified tree.
  */
 public static Ptg[] ToTokenArray(ParseNode rootNode)
 {
     TokenCollector temp = new TokenCollector(rootNode.TokenCount);
     rootNode.CollectPtgs(temp);
     return temp.GetResult();
 }
Ejemplo n.º 13
0
        public ParseNode(Ptg token, ParseNode child0, ParseNode child1)
            : this(token, new ParseNode[] { child0, child1, })
        {

        }
        /**
         * @param callerForceArrayFlag <c>true</c> if one of the current node's parents is a 
         * function Ptg which Has been Changed from default 'V' To 'A' type (due To requirements on
         * the function return value).
         */
        private void TransformNode(ParseNode node, byte desiredOperandClass,
                bool callerForceArrayFlag)
        {
            Ptg token = node.GetToken();
            ParseNode[] children = node.GetChildren();
            bool IsSimpleValueFunc = IsSimpleValueFunction(token);

            if (IsSimpleValueFunc)
            {
                bool localForceArray = desiredOperandClass == Ptg.CLASS_ARRAY;
                for (int i = 0; i < children.Length; i++)
                {
                    TransformNode(children[i], desiredOperandClass, localForceArray);
                }
                SetSimpleValueFuncClass((AbstractFunctionPtg)token, desiredOperandClass, callerForceArrayFlag);
                return;
            }
		if (IsSingleArgSum(token)) {
			// Need to process the argument of SUM with transformFunctionNode below
			// so make a dummy FuncVarPtg for that call.
			token = FuncVarPtg.SUM;
			// Note - the tAttrSum token (node.getToken()) is a base
			// token so does not need to have its operand class set
		}
            if (token is ValueOperatorPtg || token is ControlPtg
                || token is MemFuncPtg
				|| token is MemAreaPtg
				|| token is UnionPtg)
            {
                // Value Operator Ptgs and Control are base Tokens, so Token will be unchanged
                // but any child nodes are processed according To desiredOperandClass and callerForceArrayFlag

                // As per OOO documentation Sec 3.2.4 "Token Class Transformation", "Step 1"
                // All direct operands of value operators that are initially 'R' type will 
                // be converted To 'V' type.
                byte localDesiredOperandClass = desiredOperandClass == Ptg.CLASS_REF ? Ptg.CLASS_VALUE : desiredOperandClass;
                for (int i = 0; i < children.Length; i++)
                {
                    TransformNode(children[i], localDesiredOperandClass, callerForceArrayFlag);
                }
                return;
            }
            if (token is AbstractFunctionPtg)
            {
                TransformFunctionNode((AbstractFunctionPtg)token, children, desiredOperandClass, callerForceArrayFlag);
                return;
            }
            if (children.Length > 0)
            {
                //if (token == RangePtg.instance)
                if(token is OperationPtg)
                {
                    // TODO is any Token transformation required under the various ref operators?
                    return;
                }
                throw new InvalidOperationException("Node should not have any children");
            }

            if (token.IsBaseToken)
            {
                // nothing To do
                return;
            }
            token.PtgClass = (TransformClass(token.PtgClass, desiredOperandClass, callerForceArrayFlag));
        }
Ejemplo n.º 15
0
 private static ParseNode AugmentWithMemPtg(ParseNode root)
 {
     Ptg memPtg;
     if (NeedsMemFunc(root))
     {
         memPtg = new MemFuncPtg(root.EncodedSize);
     }
     else
     {
         memPtg = new MemAreaPtg(root.EncodedSize);
     }
     return new ParseNode(memPtg, root);
 }
Ejemplo n.º 16
0
 /** Parse and Translate a Math Term */
 private ParseNode Term()
 {
     ParseNode result = PowerFactor();
     while (true)
     {
         SkipWhite();
         Ptg operator1;
         switch (look)
         {
             case '*':
                 Match('*');
                 operator1 = MultiplyPtg.instance;
                 break;
             case '/':
                 Match('/');
                 operator1 = DividePtg.instance;
                 break;
             default:
                 return result; // finished with Term
         }
         ParseNode other = PowerFactor();
         result = new ParseNode(operator1, result, other);
     }
 }
Ejemplo n.º 17
0
        /**
 * From OOO doc: "Whenever one operand of the reference subexpression is a function,
 *  a defined name, a 3D reference, or an external reference (and no error occurs),
 *  a tMemFunc token is used"
 *
 */
        private static bool NeedsMemFunc(ParseNode root)
        {
            Ptg token = root.GetToken();
            if (token is AbstractFunctionPtg)
            {
                return true;
            }
            if (token is IExternSheetReferenceToken)
            { // 3D refs
                return true;
            }
            if (token is NamePtg || token is NameXPtg)
            { // 3D refs
                return true;
            }

            if (token is OperationPtg || token is ParenthesisPtg)
            {
                // expect RangePtg, but perhaps also UnionPtg, IntersectionPtg etc
                foreach (ParseNode child in root.GetChildren())
                {
                    if (NeedsMemFunc(child))
                    {
                        return true;
                    }
                }
                return false;
            }
            if (token is OperandPtg)
            {
                return false;
            }
            if (token is OperationPtg)
            {
                return true;
            }

            return false;
        }
Ejemplo n.º 18
0
 private ParseNode ComparisonExpression()
 {
     ParseNode result = ConcatExpression();
     while (true)
     {
         SkipWhite();
         switch (look)
         {
             case '=':
             case '>':
             case '<':
                 Ptg comparisonToken = GetComparisonToken();
                 ParseNode other = ConcatExpression();
                 result = new ParseNode(comparisonToken, result, other);
                 continue;
         }
         return result; // finished with predicate expression
     }
 }
Ejemplo n.º 19
0
        /**
          * @return false if sub-expression represented the specified ParseNode definitely
          * cannot appear on either side of the range (':') operator
          */
        private bool IsValidRangeOperand(ParseNode a)
        {
            Ptg tkn = a.GetToken();
            // Note - order is important for these instance-of checks
            if (tkn is OperandPtg)
            {
                // notably cell refs and area refs
                return true;
            }

            // next 2 are special cases of OperationPtg
            if (tkn is AbstractFunctionPtg)
            {
                AbstractFunctionPtg afp = (AbstractFunctionPtg)tkn;
                byte returnClass = afp.DefaultOperandClass;
                return Ptg.CLASS_REF == returnClass;
            }
            if (tkn is ValueOperatorPtg)
            {
                return false;
            }
            if (tkn is OperationPtg)
            {
                return true;
            }

            // one special case of ControlPtg
            if (tkn is ParenthesisPtg)
            {
                // parenthesis Ptg should have only one child
                return IsValidRangeOperand(a.GetChildren()[0]);
            }

            // one special case of ScalarConstantPtg
            if (tkn == ErrPtg.REF_INVALID)
            {
                return true;
            }

            // All other ControlPtgs and ScalarConstantPtgs cannot be used with ':'
            return false;
        }
        private void TransformFunctionNode(AbstractFunctionPtg afp, ParseNode[] children,
                byte desiredOperandClass, bool callerForceArrayFlag)
        {

            bool localForceArrayFlag;
            byte defaultReturnOperandClass = afp.DefaultOperandClass;

            if (callerForceArrayFlag)
            {
                switch (defaultReturnOperandClass)
                {
                    case Ptg.CLASS_REF:
                        if (desiredOperandClass == Ptg.CLASS_REF)
                        {
                            afp.PtgClass = (Ptg.CLASS_REF);
                        }
                        else
                        {
                            afp.PtgClass = (Ptg.CLASS_ARRAY);
                        }
                        localForceArrayFlag = false;
                        break;
                    case Ptg.CLASS_ARRAY:
                        afp.PtgClass = (Ptg.CLASS_ARRAY);
                        localForceArrayFlag = false;
                        break;
                    case Ptg.CLASS_VALUE:
                        afp.PtgClass = (Ptg.CLASS_ARRAY);
                        localForceArrayFlag = true;
                        break;
                    default:
                        throw new InvalidOperationException("Unexpected operand class ("
                                + defaultReturnOperandClass + ")");
                }
            }
            else
            {
                if (defaultReturnOperandClass == desiredOperandClass)
                {
                    localForceArrayFlag = false;
                    // an alternative would have been To for non-base Ptgs To Set their operand class 
                    // from their default, but this would require the call in many subclasses because
                    // the default OC is not known until the end of the constructor
                    afp.PtgClass = (defaultReturnOperandClass);
                }
                else
                {
                    switch (desiredOperandClass)
                    {
                        case Ptg.CLASS_VALUE:
                            // always OK To Set functions To return 'value'
                            afp.PtgClass = (Ptg.CLASS_VALUE);
                            localForceArrayFlag = false;
                            break;
                        case Ptg.CLASS_ARRAY:
                            switch (defaultReturnOperandClass)
                            {
                                case Ptg.CLASS_REF:
                                    afp.PtgClass = (Ptg.CLASS_REF);
                                    //								afp.SetClass(Ptg.CLASS_ARRAY);
                                    break;
                                case Ptg.CLASS_VALUE:
                                    afp.PtgClass = (Ptg.CLASS_ARRAY);
                                    break;
                                default:
                                    throw new InvalidOperationException("Unexpected operand class ("
                                            + defaultReturnOperandClass + ")");
                            }
                            localForceArrayFlag = (defaultReturnOperandClass == Ptg.CLASS_VALUE);
                            break;
                        case Ptg.CLASS_REF:
                            switch (defaultReturnOperandClass)
                            {
                                case Ptg.CLASS_ARRAY:
                                    afp.PtgClass=(Ptg.CLASS_ARRAY);
                                    break;
                                case Ptg.CLASS_VALUE:
                                    afp.PtgClass=(Ptg.CLASS_VALUE);
                                    break;
                                default:
                                    throw new InvalidOperationException("Unexpected operand class ("
                                            + defaultReturnOperandClass + ")");
                            }
                            localForceArrayFlag = false;
                            break;
                        default:
                            throw new InvalidOperationException("Unexpected operand class ("
                                    + desiredOperandClass + ")");
                    }

                }
            }

            for (int i = 0; i < children.Length; i++)
            {
                ParseNode child = children[i];
                byte paramOperandClass = afp.GetParameterClass(i);
                TransformNode(child, paramOperandClass, localForceArrayFlag);
            }
        }