Validate and parse a formula string

@param	string		$formula		Formula to parse
@return	array
@throws	PHPExcel_Calculation_Exception
545607
public function parseFormula($formula) {
		//	Basic validation that this is indeed a formula
		//	We return an empty array if not
		$formula = trim($formula);
		if ((!isset($formula{0})) || ($formula{0} != '=')) return array();
		$formula = ltrim(substr($formula,1));
		if (!isset($formula{0})) return array();

		//	Parse the formula and return the token stack
		return $this->_parseFormula($formula);
	}
156168
public function getReplacements(Formula $formula)
    {
        $result = array();

        $start = $this->getOption('separator_start');
        $end   = $this->getOption('separator_end');

        if (preg_match_all('/'. $start . '(.+?)' . $end . '/is', $this->prepare($formula->formula), $matches)) {
            $result = array_merge($result, $matches[1]);
        }

        foreach ($formula->getSubFormulas() as $key => $subformula) {
            $result = array_merge($result, $this->getReplacements($subformula));
            unset($result[array_search($key, $result)]);
        }

        return array_unique($result);
    }
371379
protected function _raiseFormulaError($errorMessage) {
		$this->formulaError = $errorMessage;
		$this->_cyclicReferenceStack->clear();
		if (!$this->suppressFormulaErrors) throw new PHPExcel_Calculation_Exception($errorMessage);
		trigger_error($errorMessage, E_USER_ERROR);
	}
695793
protected function parse($object)
    {
        if (! is_object($object)) {
            throw new ValidationException('Resource has to be an object, "' . gettype($object) . '" given.');
        }

        if (! property_exists($object, 'type')) {
            throw new ValidationException('A resource object MUST contain a type');
        }

        if (! property_exists($object, 'id')) {
            throw new ValidationException('A resource object MUST contain an id');
        }

        if (is_object($object->type) or is_array($object->type)) {
            throw new ValidationException('Resource type cannot be an array or object');
        }

        if (is_object($object->id) or is_array($object->id)) {
            throw new ValidationException('Resource Id cannot be an array or object');
        }

        $this->set('type', strval($object->type));
        $this->set('id', strval($object->id));

        if (property_exists($object, 'meta')) {
            $this->set('meta', $this->create('Meta', $object->meta));
        }
    }
655598
private function _parseFormula($formula, PHPExcel_Cell $pCell = null)
    {
        if (($formula = $this->convertMatrixReferences(trim($formula))) === false) {
            return false;
        }

        //    If we're using cell caching, then $pCell may well be flushed back to the cache (which detaches the parent worksheet),
        //        so we store the parent worksheet so that we can re-attach it when necessary
        $pCellParent = ($pCell !== null) ? $pCell->getWorksheet() : null;

        $regexpMatchString = '/^('.self::CALCULATION_REGEXP_FUNCTION.
                               '|'.self::CALCULATION_REGEXP_CELLREF.
                               '|'.self::CALCULATION_REGEXP_NUMBER.
                               '|'.self::CALCULATION_REGEXP_STRING.
                               '|'.self::CALCULATION_REGEXP_OPENBRACE.
                               '|'.self::CALCULATION_REGEXP_NAMEDRANGE.
                               '|'.self::CALCULATION_REGEXP_ERROR.
                             ')/si';

        //    Start with initialisation
        $index = 0;
        $stack = new PHPExcel_Calculation_Token_Stack;
        $output = array();
        $expectingOperator = false;                    //    We use this test in syntax-checking the expression to determine when a
                                                    //        - is a negation or + is a positive operator rather than an operation
        $expectingOperand = false;                    //    We use this test in syntax-checking the expression to determine whether an operand
                                                    //        should be null in a function call
        //    The guts of the lexical parser
        //    Loop through the formula extracting each operator and operand in turn
        while (true) {
//echo 'Assessing Expression '.substr($formula, $index), PHP_EOL;
            $opCharacter = $formula{$index};    //    Get the first character of the value at the current index position
//echo 'Initial character of expression block is '.$opCharacter, PHP_EOL;
            if ((isset(self::$comparisonOperators[$opCharacter])) && (strlen($formula) > $index) && (isset(self::$comparisonOperators[$formula{$index+1}]))) {
                $opCharacter .= $formula{++$index};
//echo 'Initial character of expression block is comparison operator '.$opCharacter.PHP_EOL;
            }

            //    Find out if we're currently at the beginning of a number, variable, cell reference, function, parenthesis or operand
            $isOperandOrFunction = preg_match($regexpMatchString, substr($formula, $index), $match);
//echo '$isOperandOrFunction is '.(($isOperandOrFunction) ? 'True' : 'False').PHP_EOL;
//var_dump($match);

            if ($opCharacter == '-' && !$expectingOperator) {                //    Is it a negation instead of a minus?
//echo 'Element is a Negation operator', PHP_EOL;
                $stack->push('Unary Operator', '~');                            //    Put a negation on the stack
                ++$index;                                                    //        and drop the negation symbol
            } elseif ($opCharacter == '%' && $expectingOperator) {
//echo 'Element is a Percentage operator', PHP_EOL;
                $stack->push('Unary Operator', '%');                            //    Put a percentage on the stack
                ++$index;
            } elseif ($opCharacter == '+' && !$expectingOperator) {            //    Positive (unary plus rather than binary operator plus) can be discarded?
//echo 'Element is a Positive number, not Plus operator', PHP_EOL;
                ++$index;                                                    //    Drop the redundant plus symbol
            } elseif ((($opCharacter == '~') || ($opCharacter == '|')) && (!$isOperandOrFunction)) {    //    We have to explicitly deny a tilde or pipe, because they are legal
                return $this->raiseFormulaError("Formula Error: Illegal character '~'");                //        on the stack but not in the input expression

            } elseif ((isset(self::$operators[$opCharacter]) or $isOperandOrFunction) && $expectingOperator) {    //    Are we putting an operator on the stack?
//echo 'Element with value '.$opCharacter.' is an Operator', PHP_EOL;
                while ($stack->count() > 0 &&
                    ($o2 = $stack->last()) &&
                    isset(self::$operators[$o2['value']]) &&
                    @(self::$operatorAssociativity[$opCharacter] ? self::$operatorPrecedence[$opCharacter] < self::$operatorPrecedence[$o2['value']] : self::$operatorPrecedence[$opCharacter] <= self::$operatorPrecedence[$o2['value']])) {
                    $output[] = $stack->pop();                                //    Swap operands and higher precedence operators from the stack to the output
                }
                $stack->push('Binary Operator', $opCharacter);    //    Finally put our current operator onto the stack
                ++$index;
                $expectingOperator = false;

            } elseif ($opCharacter == ')' && $expectingOperator) {            //    Are we expecting to close a parenthesis?
//echo 'Element is a Closing bracket', PHP_EOL;
                $expectingOperand = false;
                while (($o2 = $stack->pop()) && $o2['value'] != '(') {        //    Pop off the stack back to the last (
                    if ($o2 === null) {
                        return $this->raiseFormulaError('Formula Error: Unexpected closing brace ")"');
                    } else {
                        $output[] = $o2;
                    }
                }
                $d = $stack->last(2);
                if (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $d['value'], $matches)) {    //    Did this parenthesis just close a function?
                    $functionName = $matches[1];                                        //    Get the function name
//echo 'Closed Function is '.$functionName, PHP_EOL;
                    $d = $stack->pop();
                    $argumentCount = $d['value'];        //    See how many arguments there were (argument count is the next value stored on the stack)
//if ($argumentCount == 0) {
//    echo 'With no arguments', PHP_EOL;
//} elseif ($argumentCount == 1) {
//    echo 'With 1 argument', PHP_EOL;
//} else {
//    echo 'With '.$argumentCount.' arguments', PHP_EOL;
//}
                    $output[] = $d;                        //    Dump the argument count on the output
                    $output[] = $stack->pop();            //    Pop the function and push onto the output
                    if (isset(self::$controlFunctions[$functionName])) {
//echo 'Built-in function '.$functionName, PHP_EOL;
                        $expectedArgumentCount = self::$controlFunctions[$functionName]['argumentCount'];
                        $functionCall = self::$controlFunctions[$functionName]['functionCall'];
                    } elseif (isset(self::$PHPExcelFunctions[$functionName])) {
//echo 'PHPExcel function '.$functionName, PHP_EOL;
                        $expectedArgumentCount = self::$PHPExcelFunctions[$functionName]['argumentCount'];
                        $functionCall = self::$PHPExcelFunctions[$functionName]['functionCall'];
                    } else {    // did we somehow push a non-function on the stack? this should never happen
                        return $this->raiseFormulaError("Formula Error: Internal error, non-function on stack");
                    }
                    //    Check the argument count
                    $argumentCountError = false;
                    if (is_numeric($expectedArgumentCount)) {
                        if ($expectedArgumentCount < 0) {
//echo '$expectedArgumentCount is between 0 and '.abs($expectedArgumentCount), PHP_EOL;
                            if ($argumentCount > abs($expectedArgumentCount)) {
                                $argumentCountError = true;
                                $expectedArgumentCountString = 'no more than '.abs($expectedArgumentCount);
                            }
                        } else {
//echo '$expectedArgumentCount is numeric '.$expectedArgumentCount, PHP_EOL;
                            if ($argumentCount != $expectedArgumentCount) {
                                $argumentCountError = true;
                                $expectedArgumentCountString = $expectedArgumentCount;
                            }
                        }
                    } elseif ($expectedArgumentCount != '*') {
                        $isOperandOrFunction = preg_match('/(\d*)([-+,])(\d*)/', $expectedArgumentCount, $argMatch);
//print_r($argMatch);
//echo PHP_EOL;
                        switch ($argMatch[2]) {
                            case '+':
                                if ($argumentCount < $argMatch[1]) {
                                    $argumentCountError = true;
                                    $expectedArgumentCountString = $argMatch[1].' or more ';
                                }
                                break;
                            case '-':
                                if (($argumentCount < $argMatch[1]) || ($argumentCount > $argMatch[3])) {
                                    $argumentCountError = true;
                                    $expectedArgumentCountString = 'between '.$argMatch[1].' and '.$argMatch[3];
                                }
                                break;
                            case ',':
                                if (($argumentCount != $argMatch[1]) && ($argumentCount != $argMatch[3])) {
                                    $argumentCountError = true;
                                    $expectedArgumentCountString = 'either '.$argMatch[1].' or '.$argMatch[3];
                                }
                                break;
                        }
                    }
                    if ($argumentCountError) {
                        return $this->raiseFormulaError("Formula Error: Wrong number of arguments for $functionName() function: $argumentCount given, ".$expectedArgumentCountString." expected");
                    }
                }
                ++$index;

            } elseif ($opCharacter == ',') {            //    Is this the separator for function arguments?
//echo 'Element is a Function argument separator', PHP_EOL;
                while (($o2 = $stack->pop()) && $o2['value'] != '(') {        //    Pop off the stack back to the last (
                    if ($o2 === null) {
                        return $this->raiseFormulaError("Formula Error: Unexpected ,");
                    } else {
                        $output[] = $o2;    // pop the argument expression stuff and push onto the output
                    }
                }
                //    If we've a comma when we're expecting an operand, then what we actually have is a null operand;
                //        so push a null onto the stack
                if (($expectingOperand) || (!$expectingOperator)) {
                    $output[] = array('type' => 'NULL Value', 'value' => self::$excelConstants['NULL'], 'reference' => null);
                }
                // make sure there was a function
                $d = $stack->last(2);
                if (!preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $d['value'], $matches)) {
                    return $this->raiseFormulaError("Formula Error: Unexpected ,");
                }
                $d = $stack->pop();
                $stack->push($d['type'], ++$d['value'], $d['reference']);    // increment the argument count
                $stack->push('Brace', '(');    // put the ( back on, we'll need to pop back to it again
                $expectingOperator = false;
                $expectingOperand = true;
                ++$index;

            } elseif ($opCharacter == '(' && !$expectingOperator) {
//                echo 'Element is an Opening Bracket<br />';
                $stack->push('Brace', '(');
                ++$index;

            } elseif ($isOperandOrFunction && !$expectingOperator) {    // do we now have a function/variable/number?
                $expectingOperator = true;
                $expectingOperand = false;
                $val = $match[1];
                $length = strlen($val);
//                echo 'Element with value '.$val.' is an Operand, Variable, Constant, String, Number, Cell Reference or Function<br />';

                if (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $val, $matches)) {
                    $val = preg_replace('/\s/u', '', $val);
//                    echo 'Element '.$val.' is a Function<br />';
                    if (isset(self::$PHPExcelFunctions[strtoupper($matches[1])]) || isset(self::$controlFunctions[strtoupper($matches[1])])) {    // it's a function
                        $stack->push('Function', strtoupper($val));
                        $ax = preg_match('/^\s*(\s*\))/ui', substr($formula, $index+$length), $amatch);
                        if ($ax) {
                            $stack->push('Operand Count for Function '.strtoupper($val).')', 0);
                            $expectingOperator = true;
                        } else {
                            $stack->push('Operand Count for Function '.strtoupper($val).')', 1);
                            $expectingOperator = false;
                        }
                        $stack->push('Brace', '(');
                    } else {    // it's a var w/ implicit multiplication
                        $output[] = array('type' => 'Value', 'value' => $matches[1], 'reference' => null);
                    }
                } elseif (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $val, $matches)) {
//                    echo 'Element '.$val.' is a Cell reference<br />';
                    //    Watch for this case-change when modifying to allow cell references in different worksheets...
                    //    Should only be applied to the actual cell column, not the worksheet name

                    //    If the last entry on the stack was a : operator, then we have a cell range reference
                    $testPrevOp = $stack->last(1);
                    if ($testPrevOp['value'] == ':') {
                        //    If we have a worksheet reference, then we're playing with a 3D reference
                        if ($matches[2] == '') {
                            //    Otherwise, we 'inherit' the worksheet reference from the start cell reference
                            //    The start of the cell range reference should be the last entry in $output
                            $startCellRef = $output[count($output)-1]['value'];
                            preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $startCellRef, $startMatches);
                            if ($startMatches[2] > '') {
                                $val = $startMatches[2].'!'.$val;
                            }
                        } else {
                            return $this->raiseFormulaError("3D Range references are not yet supported");
                        }
                    }

                    $output[] = array('type' => 'Cell Reference', 'value' => $val, 'reference' => $val);
//                    $expectingOperator = FALSE;
                } else {    // it's a variable, constant, string, number or boolean
//                    echo 'Element is a Variable, Constant, String, Number or Boolean<br />';
                    //    If the last entry on the stack was a : operator, then we may have a row or column range reference
                    $testPrevOp = $stack->last(1);
                    if ($testPrevOp['value'] == ':') {
                        $startRowColRef = $output[count($output)-1]['value'];
                        $rangeWS1 = '';
                        if (strpos('!', $startRowColRef) !== false) {
                            list($rangeWS1, $startRowColRef) = explode('!', $startRowColRef);
                        }
                        if ($rangeWS1 != '') {
                            $rangeWS1 .= '!';
                        }
                        $rangeWS2 = $rangeWS1;
                        if (strpos('!', $val) !== false) {
                            list($rangeWS2, $val) = explode('!', $val);
                        }
                        if ($rangeWS2 != '') {
                            $rangeWS2 .= '!';
                        }
                        if ((is_integer($startRowColRef)) && (ctype_digit($val)) &&
                            ($startRowColRef <= 1048576) && ($val <= 1048576)) {
                            //    Row range
                            $endRowColRef = ($pCellParent !== null) ? $pCellParent->getHighestColumn() : 'XFD';    //    Max 16,384 columns for Excel2007
                            $output[count($output)-1]['value'] = $rangeWS1.'A'.$startRowColRef;
                            $val = $rangeWS2.$endRowColRef.$val;
                        } elseif ((ctype_alpha($startRowColRef)) && (ctype_alpha($val)) &&
                            (strlen($startRowColRef) <= 3) && (strlen($val) <= 3)) {
                            //    Column range
                            $endRowColRef = ($pCellParent !== null) ? $pCellParent->getHighestRow() : 1048576;        //    Max 1,048,576 rows for Excel2007
                            $output[count($output)-1]['value'] = $rangeWS1.strtoupper($startRowColRef).'1';
                            $val = $rangeWS2.$val.$endRowColRef;
                        }
                    }

                    $localeConstant = false;
                    if ($opCharacter == '"') {
//                        echo 'Element is a String<br />';
                        //    UnEscape any quotes within the string
                        $val = self::wrapResult(str_replace('""', '"', self::unwrapResult($val)));
                    } elseif (is_numeric($val)) {
//                        echo 'Element is a Number<br />';
                        if ((strpos($val, '.') !== false) || (stripos($val, 'e') !== false) || ($val > PHP_INT_MAX) || ($val < -PHP_INT_MAX)) {
//                            echo 'Casting '.$val.' to float<br />';
                            $val = (float) $val;
                        } else {
//                            echo 'Casting '.$val.' to integer<br />';
                            $val = (integer) $val;
                        }
                    } elseif (isset(self::$excelConstants[trim(strtoupper($val))])) {
                        $excelConstant = trim(strtoupper($val));
//                        echo 'Element '.$excelConstant.' is an Excel Constant<br />';
                        $val = self::$excelConstants[$excelConstant];
                    } elseif (($localeConstant = array_search(trim(strtoupper($val)), self::$localeBoolean)) !== false) {
//                        echo 'Element '.$localeConstant.' is an Excel Constant<br />';
                        $val = self::$excelConstants[$localeConstant];
                    }
                    $details = array('type' => 'Value', 'value' => $val, 'reference' => null);
                    if ($localeConstant) {
                        $details['localeValue'] = $localeConstant;
                    }
                    $output[] = $details;
                }
                $index += $length;

            } elseif ($opCharacter == '$') {    // absolute row or column range
                ++$index;
            } elseif ($opCharacter == ')') {    // miscellaneous error checking
                if ($expectingOperand) {
                    $output[] = array('type' => 'NULL Value', 'value' => self::$excelConstants['NULL'], 'reference' => null);
                    $expectingOperand = false;
                    $expectingOperator = true;
                } else {
                    return $this->raiseFormulaError("Formula Error: Unexpected ')'");
                }
            } elseif (isset(self::$operators[$opCharacter]) && !$expectingOperator) {
                return $this->raiseFormulaError("Formula Error: Unexpected operator '$opCharacter'");
            } else {    // I don't even want to know what you did to get here
                return $this->raiseFormulaError("Formula Error: An unexpected error occured");
            }
            //    Test for end of formula string
            if ($index == strlen($formula)) {
                //    Did we end with an operator?.
                //    Only valid for the % unary operator
                if ((isset(self::$operators[$opCharacter])) && ($opCharacter != '%')) {
                    return $this->raiseFormulaError("Formula Error: Operator '$opCharacter' has no operands");
                } else {
                    break;
                }
            }
            //    Ignore white space
            while (($formula{$index} == "\n") || ($formula{$index} == "\r")) {
                ++$index;
            }
            if ($formula{$index} == ' ') {
                while ($formula{$index} == ' ') {
                    ++$index;
                }
                //    If we're expecting an operator, but only have a space between the previous and next operands (and both are
                //        Cell References) then we have an INTERSECTION operator
//                echo 'Possible Intersect Operator<br />';
                if (($expectingOperator) && (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'.*/Ui', substr($formula, $index), $match)) &&
                    ($output[count($output)-1]['type'] == 'Cell Reference')) {
//                    echo 'Element is an Intersect Operator<br />';
                    while ($stack->count() > 0 &&
                        ($o2 = $stack->last()) &&
                        isset(self::$operators[$o2['value']]) &&
                        @(self::$operatorAssociativity[$opCharacter] ? self::$operatorPrecedence[$opCharacter] < self::$operatorPrecedence[$o2['value']] : self::$operatorPrecedence[$opCharacter] <= self::$operatorPrecedence[$o2['value']])) {
                        $output[] = $stack->pop();                                //    Swap operands and higher precedence operators from the stack to the output
                    }
                    $stack->push('Binary Operator', '|');    //    Put an Intersect Operator on the stack
                    $expectingOperator = false;
                }
            }
        }

        while (($op = $stack->pop()) !== null) {    // pop everything off the stack and push onto output
            if ((is_array($op) && $op['value'] == '(') || ($op === '(')) {
                return $this->raiseFormulaError("Formula Error: Expecting ')'");    // if there are any opening braces on the stack, then braces were unbalanced
            }
            $output[] = $op;
        }
        return $output;
    }
778293
public function bindValue(PHPExcel_Cell $cell, $value = null)
    {
        // sanitize UTF-8 strings
        if (is_string($value)) {
            $value = PHPExcel_Shared_String::SanitizeUTF8($value);
        }

        // Find out data type
        $dataType = parent::dataTypeForValue($value);

        // Style logic - strings
        if ($dataType === PHPExcel_Cell_DataType::TYPE_STRING && !$value instanceof PHPExcel_RichText) {
            //    Test for booleans using locale-setting
            if ($value == PHPExcel_Calculation::getTRUE()) {
                $cell->setValueExplicit( TRUE, PHPExcel_Cell_DataType::TYPE_BOOL);
                return true;
            } elseif($value == PHPExcel_Calculation::getFALSE()) {
                $cell->setValueExplicit( FALSE, PHPExcel_Cell_DataType::TYPE_BOOL);
                return true;
            }

            // Check for number in scientific format
            if (preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_NUMBER.'$/', $value)) {
                $cell->setValueExplicit( (float) $value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
                return true;
            }

            // Check for fraction
            if (preg_match('/^([+-]?)\s*([0-9]+)\s?\/\s*([0-9]+)$/', $value, $matches)) {
                // Convert value to number
                $value = $matches[2] / $matches[3];
                if ($matches[1] == '-') $value = 0 - $value;
                $cell->setValueExplicit( (float) $value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
                // Set style
                $cell->getWorksheet()->getStyle( $cell->getCoordinate() )
                    ->getNumberFormat()->setFormatCode( '??/??' );
                return true;
            } elseif (preg_match('/^([+-]?)([0-9]*) +([0-9]*)\s?\/\s*([0-9]*)$/', $value, $matches)) {
                // Convert value to number
                $value = $matches[2] + ($matches[3] / $matches[4]);
                if ($matches[1] == '-') $value = 0 - $value;
                $cell->setValueExplicit( (float) $value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
                // Set style
                $cell->getWorksheet()->getStyle( $cell->getCoordinate() )
                    ->getNumberFormat()->setFormatCode( '# ??/??' );
                return true;
            }

            // Check for percentage
            if (preg_match('/^\-?[0-9]*\.?[0-9]*\s?\%$/', $value)) {
                // Convert value to number
                $value = (float) str_replace('%', '', $value) / 100;
                $cell->setValueExplicit( $value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
                // Set style
                $cell->getWorksheet()->getStyle( $cell->getCoordinate() )
                    ->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_PERCENTAGE_00 );
                return true;
            }

            // Check for currency
            $currencyCode = PHPExcel_Shared_String::getCurrencyCode();
            $decimalSeparator = PHPExcel_Shared_String::getDecimalSeparator();
            $thousandsSeparator = PHPExcel_Shared_String::getThousandsSeparator();
            if (preg_match('/^'.preg_quote($currencyCode).' *(\d{1,3}('.preg_quote($thousandsSeparator).'\d{3})*|(\d+))('.preg_quote($decimalSeparator).'\d{2})?$/', $value)) {
                // Convert value to number
                $value = (float) trim(str_replace(array($currencyCode, $thousandsSeparator, $decimalSeparator), array('', '', '.'), $value));
                $cell->setValueExplicit( $value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
                // Set style
                $cell->getWorksheet()->getStyle( $cell->getCoordinate() )
                    ->getNumberFormat()->setFormatCode(
                        str_replace('$', $currencyCode, PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_USD_SIMPLE )
                    );
                return true;
            } elseif (preg_match('/^\$ *(\d{1,3}(\,\d{3})*|(\d+))(\.\d{2})?$/', $value)) {
                // Convert value to number
                $value = (float) trim(str_replace(array('$',','), '', $value));
                $cell->setValueExplicit( $value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
                // Set style
                $cell->getWorksheet()->getStyle( $cell->getCoordinate() )
                    ->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_USD_SIMPLE );
                return true;
            }

            // Check for time without seconds e.g. '9:45', '09:45'
            if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d$/', $value)) {
                // Convert value to number
                list($h, $m) = explode(':', $value);
                $days = $h / 24 + $m / 1440;
                $cell->setValueExplicit($days, PHPExcel_Cell_DataType::TYPE_NUMERIC);
                // Set style
                $cell->getWorksheet()->getStyle( $cell->getCoordinate() )
                    ->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME3 );
                return true;
            }

            // Check for time with seconds '9:45:59', '09:45:59'
            if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d:[0-5]\d$/', $value)) {
                // Convert value to number
                list($h, $m, $s) = explode(':', $value);
                $days = $h / 24 + $m / 1440 + $s / 86400;
                // Convert value to number
                $cell->setValueExplicit($days, PHPExcel_Cell_DataType::TYPE_NUMERIC);
                // Set style
                $cell->getWorksheet()->getStyle( $cell->getCoordinate() )
                    ->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME4 );
                return true;
            }

            // Check for datetime, e.g. '2008-12-31', '2008-12-31 15:59', '2008-12-31 15:59:10'
            if (($d = PHPExcel_Shared_Date::stringToExcel($value)) !== false) {
                // Convert value to number
                $cell->setValueExplicit($d, PHPExcel_Cell_DataType::TYPE_NUMERIC);
                // Determine style. Either there is a time part or not. Look for ':'
                if (strpos($value, ':') !== false) {
                    $formatCode = 'yyyy-mm-dd h:mm';
                } else {
                    $formatCode = 'yyyy-mm-dd';
                }
                $cell->getWorksheet()->getStyle( $cell->getCoordinate() )
                    ->getNumberFormat()->setFormatCode($formatCode);
                return true;
            }

            // Check for newline character "\n"
            if (strpos($value, "\n") !== FALSE) {
                $value = PHPExcel_Shared_String::SanitizeUTF8($value);
                $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_STRING);
                // Set style
                $cell->getWorksheet()->getStyle( $cell->getCoordinate() )
                    ->getAlignment()->setWrapText(TRUE);
                return true;
            }
        }

        // Not bound yet? Use parent...
        return parent::bindValue($cell, $value);
    }
665317
public static function parse(string $expression): string
    {
        $expression = \trim($expression);

        if ($expression === '' || \is_numeric($expression)) {
            return $expression;
        }

        if (!isset(self::$cache[$expression])) {
            $tree = self::treeStruct($expression);
            self::$cache[$expression] = self::transform($tree);
        }

        return self::$cache[$expression];
    }
1184575
public function getDataValidation()
	{
		if (!isset($this->_parent)) {
			throw new PHPExcel_Exception('Cannot get data validation for cell that is not bound to a worksheet');
		}

		return $this->getWorksheet()->getDataValidation($this->getCoordinate());
	}
711252
private function parseExpression($expression)
    {
        // Check for URI operators
        $operator = '';

        if (isset(self::$operatorHash[$expression[0]])) {
            $operator = $expression[0];
            $expression = substr($expression, 1);
        }

        $values = explode(',', $expression);
        foreach ($values as &$value) {
            $value = trim($value);
            $varspec = array();
            $substrPos = strpos($value, ':');
            if ($substrPos) {
                $varspec['value'] = substr($value, 0, $substrPos);
                $varspec['modifier'] = ':';
                $varspec['position'] = (int) substr($value, $substrPos + 1);
            } elseif (substr($value, -1) == '*') {
                $varspec['modifier'] = '*';
                $varspec['value'] = substr($value, 0, -1);
            } else {
                $varspec['value'] = (string) $value;
                $varspec['modifier'] = '';
            }
            $value = $varspec;
        }

        return array(
            'operator' => $operator,
            'values'   => $values
        );
    }
548763
protected function parse($object)
    {
        if (! is_object($object)) {
            throw new ValidationException('ItemLink has to be an object, "' . gettype($object) . '" given.');
        }

        foreach (get_object_vars($object) as $name => $value) {
            $this->setLink($name, $value);
        }
    }
629457
public function calc_formula($formula, $params=false) {
        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
        self::__construct($formula, $params);
    }
71306
public static function unlocalize($formula) {
        $formula = str_replace(get_string('decsep', 'langconfig'), '$', $formula);
        $formula = str_replace(get_string('listsep', 'langconfig'), ',', $formula);
        $formula = str_replace('$', '.', $formula); // temp placeholder
        return $formula;
    }
1181399
protected function parseRule($rule)
	{
		$parameters = array();

		// The format for specifying validation rules and parameters follows an
		// easy {rule}:{parameters} formatting convention. For instance the
		// rule "Max:3" states that the value may only be three letters.
		if (strpos($rule, ':') !== false)
		{
			list($rule, $parameter) = explode(':', $rule, 2);

			$parameters = $this->parseParameters($rule, $parameter);
		}

		return array(studly_case($rule), $parameters);
	}
429900
public function set_calculation($formula) {
        $this->calculation = grade_item::normalize_formula($formula, $this->courseid);
        $this->calculation_normalized = true;
        return $this->update();
    }
320892
def parse_formula(formula, byte_stream = false)
    # Build the parse tree for the formula
    tokens = reverse(parse(formula))

    # Add a volatile token if the formula contains a volatile function.
    # This must be the first token in the list
    #
    tokens.unshift('_vol') if check_volatile(tokens) != 0

    # The return value depends on which Worksheet.pm method is the caller
    unless byte_stream
      # Parse formula to see if it throws any errors and then
      # return raw tokens to Worksheet::store_formula()
      #
      parse_tokens(tokens)
      tokens
    else
      # Return byte stream to Worksheet::write_formula()
      parse_tokens(tokens)
    end
  end
586293
protected function parse($object)
    {
        if (! is_object($object)) {
            throw new ValidationException('RelationshipLink has to be an object, "' . gettype($object) . '" given.');
        }

        if (! property_exists($object, 'self') and ! property_exists($object, 'related')) {
            throw new ValidationException('RelationshipLink has to be at least a "self" or "related" link');
        }

        $links = get_object_vars($object);

        if (array_key_exists('self', $links)) {
            if (! is_string($links['self'])) {
                throw new ValidationException('property "self" has to be a string, "' . gettype($links['self']) . '" given.');
            }

            $this->set('self', strval($links['self']));

            unset($links['self']);
        }

        if (array_key_exists('related', $links)) {
            if (! is_string($links['related']) and ! is_object($links['related'])) {
                throw new ValidationException('property "related" has to be a string or object, "' . gettype($links['related']) . '" given.');
            }

            $this->setLink('related', $links['related']);

            unset($links['related']);
        }

        // Pagination links
        if ($this->getParent()->has('data') and (
            $this->getParent()->get('data') instanceof ResourceIdentifierCollection or
            $this->getParent()->get('data') instanceof ResourceIdentifierCollectionInterface
        )) {
            if (array_key_exists('first', $links)) {
                $this->setPaginationLink('first', $links['first']);

                unset($links['first']);
            }

            if (array_key_exists('last', $links)) {
                $this->setPaginationLink('last', $links['last']);

                unset($links['last']);
            }

            if (array_key_exists('prev', $links)) {
                $this->setPaginationLink('prev', $links['prev']);

                unset($links['prev']);
            }

            if (array_key_exists('next', $links)) {
                $this->setPaginationLink('next', $links['next']);

                unset($links['next']);
            }
        }

        // custom links
        foreach ($links as $name => $value) {
            $this->setLink($name, $value);
        }
    }
855786
public static function normalize_formula($formula, $courseid) {
        $formula = trim($formula);

        if (empty($formula)) {
            return NULL;

        }

        // normalize formula - we want grade item ids ##giXXX## instead of [[idnumber]]
        if ($grade_items = grade_item::fetch_all(array('courseid'=>$courseid))) {
            foreach ($grade_items as $grade_item) {
                $formula = str_replace('[['.$grade_item->idnumber.']]', '##gi'.$grade_item->id.'##', $formula);
            }
        }

        return $formula;
    }