Calculate the value of a formula

@param	string			$formula	Formula to parse
@param	string			$cellID		Address of the cell to calculate
@param	PHPExcel_Cell	$pCell		Cell to calculate
@return	mixed
@throws	PHPExcel_Calculation_Exception
439935
public function calculateFormula($formula, $cellID=NULL, PHPExcel_Cell $pCell = NULL) {
		//	Initialise the logging settings
		$this->formulaError = null;
		$this->_debugLog->clearLog();
		$this->_cyclicReferenceStack->clear();

		//	Disable calculation cacheing because it only applies to cell calculations, not straight formulae
		//	But don't actually flush any cache
		$resetCache = $this->getCalculationCacheEnabled();
		$this->_calculationCacheEnabled = FALSE;
		//	Execute the calculation
		try {
			$result = self::_unwrapResult($this->_calculateFormulaValue($formula, $cellID, $pCell));
		} catch (PHPExcel_Exception $e) {
			throw new PHPExcel_Calculation_Exception($e->getMessage());
		}

		//	Reset calculation cacheing to its previous state
		$this->_calculationCacheEnabled = $resetCache;

		return $result;
	}
1170690
private function _getNextToken($formulaData, $baseCell = 'A1')
	{
		// offset: 0; size: 1; token id
		$id = ord($formulaData[0]); // token id
		$name = false; // initialize token name

		switch ($id) {
		case 0x03: $name = 'tAdd';		$size = 1;	$data = '+';	break;
		case 0x04: $name = 'tSub';		$size = 1;	$data = '-';	break;
		case 0x05: $name = 'tMul';		$size = 1;	$data = '*';	break;
		case 0x06: $name = 'tDiv';		$size = 1;	$data = '/';	break;
		case 0x07: $name = 'tPower';	$size = 1;	$data = '^';	break;
		case 0x08: $name = 'tConcat';	$size = 1;	$data = '&';	break;
		case 0x09: $name = 'tLT';		$size = 1;	$data = '<';	break;
		case 0x0A: $name = 'tLE';		$size = 1;	$data = '<=';	break;
		case 0x0B: $name = 'tEQ';		$size = 1;	$data = '=';	break;
		case 0x0C: $name = 'tGE';		$size = 1;	$data = '>=';	break;
		case 0x0D: $name = 'tGT';		$size = 1;	$data = '>';	break;
		case 0x0E: $name = 'tNE';		$size = 1;	$data = '<>';	break;
		case 0x0F: $name = 'tIsect';	$size = 1;	$data = ' ';	break;
		case 0x10: $name = 'tList';		$size = 1;	$data = ',';	break;
		case 0x11: $name = 'tRange';	$size = 1;	$data = ':';	break;
		case 0x12: $name = 'tUplus';	$size = 1;	$data = '+';	break;
		case 0x13: $name = 'tUminus';	$size = 1;	$data = '-';	break;
		case 0x14: $name = 'tPercent';	$size = 1;	$data = '%';	break;
		case 0x15:	//	parenthesis
			$name  = 'tParen';
			$size  = 1;
			$data = null;
			break;
		case 0x16:	//	missing argument
			$name = 'tMissArg';
			$size = 1;
			$data = '';
			break;
		case 0x17:	//	string
			$name = 'tStr';
			// offset: 1; size: var; Unicode string, 8-bit string length
			$string = self::_readUnicodeStringShort(substr($formulaData, 1));
			$size = 1 + $string['size'];
			$data = self::_UTF8toExcelDoubleQuoted($string['value']);
			break;
		case 0x19:	//	Special attribute
			// offset: 1; size: 1; attribute type flags:
			switch (ord($formulaData[1])) {
			case 0x01:
				$name = 'tAttrVolatile';
				$size = 4;
				$data = null;
				break;
			case 0x02:
				$name = 'tAttrIf';
				$size = 4;
				$data = null;
				break;
			case 0x04:
				$name = 'tAttrChoose';
				// offset: 2; size: 2; number of choices in the CHOOSE function ($nc, number of parameters decreased by 1)
				$nc = self::_GetInt2d($formulaData, 2);
				// offset: 4; size: 2 * $nc
				// offset: 4 + 2 * $nc; size: 2
				$size = 2 * $nc + 6;
				$data = null;
				break;
			case 0x08:
				$name = 'tAttrSkip';
				$size = 4;
				$data = null;
				break;
			case 0x10:
				$name = 'tAttrSum';
				$size = 4;
				$data = null;
				break;
			case 0x40:
			case 0x41:
				$name = 'tAttrSpace';
				$size = 4;
				// offset: 2; size: 2; space type and position
				switch (ord($formulaData[2])) {
				case 0x00:
					$spacetype = 'type0';
					break;
				case 0x01:
					$spacetype = 'type1';
					break;
				case 0x02:
					$spacetype = 'type2';
					break;
				case 0x03:
					$spacetype = 'type3';
					break;
				case 0x04:
					$spacetype = 'type4';
					break;
				case 0x05:
					$spacetype = 'type5';
					break;
				default:
					throw new PHPExcel_Reader_Exception('Unrecognized space type in tAttrSpace token');
					break;
				}
				// offset: 3; size: 1; number of inserted spaces/carriage returns
				$spacecount = ord($formulaData[3]);

				$data = array('spacetype' => $spacetype, 'spacecount' => $spacecount);
				break;
			default:
				throw new PHPExcel_Reader_Exception('Unrecognized attribute flag in tAttr token');
				break;
			}
			break;
		case 0x1C:	//	error code
			// offset: 1; size: 1; error code
			$name = 'tErr';
			$size = 2;
			$data = self::_mapErrorCode(ord($formulaData[1]));
			break;
		case 0x1D:	//	boolean
			// offset: 1; size: 1; 0 = false, 1 = true;
			$name = 'tBool';
			$size = 2;
			$data = ord($formulaData[1]) ? 'TRUE' : 'FALSE';
			break;
		case 0x1E:	//	integer
			// offset: 1; size: 2; unsigned 16-bit integer
			$name = 'tInt';
			$size = 3;
			$data = self::_GetInt2d($formulaData, 1);
			break;
		case 0x1F:	//	number
			// offset: 1; size: 8;
			$name = 'tNum';
			$size = 9;
			$data = self::_extractNumber(substr($formulaData, 1));
			$data = str_replace(',', '.', (string)$data); // in case non-English locale
			break;
		case 0x20:	//	array constant
		case 0x40:
		case 0x60:
			// offset: 1; size: 7; not used
			$name = 'tArray';
			$size = 8;
			$data = null;
			break;
		case 0x21:	//	function with fixed number of arguments
		case 0x41:
		case 0x61:
			$name = 'tFunc';
			$size = 3;
			// offset: 1; size: 2; index to built-in sheet function
			switch (self::_GetInt2d($formulaData, 1)) {
			case   2: $function = 'ISNA'; 			$args = 1; 	break;
			case   3: $function = 'ISERROR'; 		$args = 1; 	break;
			case  10: $function = 'NA'; 			$args = 0; 	break;
			case  15: $function = 'SIN'; 			$args = 1; 	break;
			case  16: $function = 'COS'; 			$args = 1; 	break;
			case  17: $function = 'TAN'; 			$args = 1; 	break;
			case  18: $function = 'ATAN'; 			$args = 1; 	break;
			case  19: $function = 'PI'; 			$args = 0; 	break;
			case  20: $function = 'SQRT'; 			$args = 1; 	break;
			case  21: $function = 'EXP'; 			$args = 1; 	break;
			case  22: $function = 'LN'; 			$args = 1; 	break;
			case  23: $function = 'LOG10'; 			$args = 1; 	break;
			case  24: $function = 'ABS'; 			$args = 1; 	break;
			case  25: $function = 'INT'; 			$args = 1; 	break;
			case  26: $function = 'SIGN'; 			$args = 1; 	break;
			case  27: $function = 'ROUND'; 			$args = 2; 	break;
			case  30: $function = 'REPT'; 			$args = 2; 	break;
			case  31: $function = 'MID'; 			$args = 3; 	break;
			case  32: $function = 'LEN'; 			$args = 1; 	break;
			case  33: $function = 'VALUE'; 			$args = 1; 	break;
			case  34: $function = 'TRUE'; 			$args = 0; 	break;
			case  35: $function = 'FALSE'; 			$args = 0; 	break;
			case  38: $function = 'NOT'; 			$args = 1; 	break;
			case  39: $function = 'MOD'; 			$args = 2;	break;
			case  40: $function = 'DCOUNT'; 		$args = 3;	break;
			case  41: $function = 'DSUM'; 			$args = 3;	break;
			case  42: $function = 'DAVERAGE'; 		$args = 3;	break;
			case  43: $function = 'DMIN'; 			$args = 3;	break;
			case  44: $function = 'DMAX'; 			$args = 3;	break;
			case  45: $function = 'DSTDEV'; 		$args = 3;	break;
			case  48: $function = 'TEXT'; 			$args = 2;	break;
			case  61: $function = 'MIRR'; 			$args = 3;	break;
			case  63: $function = 'RAND'; 			$args = 0;	break;
			case  65: $function = 'DATE'; 			$args = 3;	break;
			case  66: $function = 'TIME'; 			$args = 3;	break;
			case  67: $function = 'DAY'; 			$args = 1;	break;
			case  68: $function = 'MONTH'; 			$args = 1;	break;
			case  69: $function = 'YEAR'; 			$args = 1;	break;
			case  71: $function = 'HOUR'; 			$args = 1;	break;
			case  72: $function = 'MINUTE'; 		$args = 1;	break;
			case  73: $function = 'SECOND'; 		$args = 1;	break;
			case  74: $function = 'NOW'; 			$args = 0;	break;
			case  75: $function = 'AREAS'; 			$args = 1;	break;
			case  76: $function = 'ROWS'; 			$args = 1;	break;
			case  77: $function = 'COLUMNS'; 		$args = 1;	break;
			case  83: $function = 'TRANSPOSE'; 		$args = 1;	break;
			case  86: $function = 'TYPE'; 			$args = 1;	break;
			case  97: $function = 'ATAN2'; 			$args = 2;	break;
			case  98: $function = 'ASIN'; 			$args = 1;	break;
			case  99: $function = 'ACOS'; 			$args = 1;	break;
			case 105: $function = 'ISREF'; 			$args = 1;	break;
			case 111: $function = 'CHAR'; 			$args = 1;	break;
			case 112: $function = 'LOWER'; 			$args = 1;	break;
			case 113: $function = 'UPPER'; 			$args = 1;	break;
			case 114: $function = 'PROPER'; 		$args = 1;	break;
			case 117: $function = 'EXACT'; 			$args = 2;	break;
			case 118: $function = 'TRIM'; 			$args = 1;	break;
			case 119: $function = 'REPLACE'; 		$args = 4;	break;
			case 121: $function = 'CODE'; 			$args = 1;	break;
			case 126: $function = 'ISERR'; 			$args = 1;	break;
			case 127: $function = 'ISTEXT'; 		$args = 1;	break;
			case 128: $function = 'ISNUMBER'; 		$args = 1;	break;
			case 129: $function = 'ISBLANK'; 		$args = 1;	break;
			case 130: $function = 'T'; 				$args = 1;	break;
			case 131: $function = 'N'; 				$args = 1;	break;
			case 140: $function = 'DATEVALUE'; 		$args = 1;	break;
			case 141: $function = 'TIMEVALUE'; 		$args = 1;	break;
			case 142: $function = 'SLN'; 			$args = 3;	break;
			case 143: $function = 'SYD'; 			$args = 4;	break;
			case 162: $function = 'CLEAN'; 			$args = 1;	break;
			case 163: $function = 'MDETERM'; 		$args = 1;	break;
			case 164: $function = 'MINVERSE'; 		$args = 1;	break;
			case 165: $function = 'MMULT'; 			$args = 2;	break;
			case 184: $function = 'FACT'; 			$args = 1;	break;
			case 189: $function = 'DPRODUCT'; 		$args = 3;	break;
			case 190: $function = 'ISNONTEXT'; 		$args = 1;	break;
			case 195: $function = 'DSTDEVP'; 		$args = 3;	break;
			case 196: $function = 'DVARP'; 			$args = 3;	break;
			case 198: $function = 'ISLOGICAL'; 		$args = 1;	break;
			case 199: $function = 'DCOUNTA'; 		$args = 3;	break;
			case 207: $function = 'REPLACEB'; 		$args = 4;	break;
			case 210: $function = 'MIDB'; 			$args = 3;	break;
			case 211: $function = 'LENB'; 			$args = 1;	break;
			case 212: $function = 'ROUNDUP'; 		$args = 2;	break;
			case 213: $function = 'ROUNDDOWN'; 		$args = 2;	break;
			case 214: $function = 'ASC'; 			$args = 1;	break;
			case 215: $function = 'DBCS'; 			$args = 1;	break;
			case 221: $function = 'TODAY'; 			$args = 0;	break;
			case 229: $function = 'SINH'; 			$args = 1;	break;
			case 230: $function = 'COSH'; 			$args = 1;	break;
			case 231: $function = 'TANH'; 			$args = 1;	break;
			case 232: $function = 'ASINH'; 			$args = 1;	break;
			case 233: $function = 'ACOSH'; 			$args = 1;	break;
			case 234: $function = 'ATANH'; 			$args = 1;	break;
			case 235: $function = 'DGET'; 			$args = 3;	break;
			case 244: $function = 'INFO'; 			$args = 1;	break;
			case 252: $function = 'FREQUENCY'; 		$args = 2;	break;
			case 261: $function = 'ERROR.TYPE'; 	$args = 1;	break;
			case 271: $function = 'GAMMALN'; 		$args = 1;	break;
			case 273: $function = 'BINOMDIST'; 		$args = 4;	break;
			case 274: $function = 'CHIDIST'; 		$args = 2;	break;
			case 275: $function = 'CHIINV'; 		$args = 2;	break;
			case 276: $function = 'COMBIN'; 		$args = 2;	break;
			case 277: $function = 'CONFIDENCE'; 	$args = 3;	break;
			case 278: $function = 'CRITBINOM'; 		$args = 3;	break;
			case 279: $function = 'EVEN'; 			$args = 1;	break;
			case 280: $function = 'EXPONDIST'; 		$args = 3;	break;
			case 281: $function = 'FDIST'; 			$args = 3;	break;
			case 282: $function = 'FINV'; 			$args = 3;	break;
			case 283: $function = 'FISHER'; 		$args = 1;	break;
			case 284: $function = 'FISHERINV'; 		$args = 1;	break;
			case 285: $function = 'FLOOR'; 			$args = 2;	break;
			case 286: $function = 'GAMMADIST'; 		$args = 4;	break;
			case 287: $function = 'GAMMAINV'; 		$args = 3;	break;
			case 288: $function = 'CEILING'; 		$args = 2;	break;
			case 289: $function = 'HYPGEOMDIST';	$args = 4;	break;
			case 290: $function = 'LOGNORMDIST';	$args = 3;	break;
			case 291: $function = 'LOGINV';			$args = 3;	break;
			case 292: $function = 'NEGBINOMDIST';	$args = 3;	break;
			case 293: $function = 'NORMDIST';		$args = 4;	break;
			case 294: $function = 'NORMSDIST';		$args = 1;	break;
			case 295: $function = 'NORMINV';		$args = 3;	break;
			case 296: $function = 'NORMSINV';		$args = 1;	break;
			case 297: $function = 'STANDARDIZE';	$args = 3;	break;
			case 298: $function = 'ODD';			$args = 1;	break;
			case 299: $function = 'PERMUT';			$args = 2;	break;
			case 300: $function = 'POISSON';		$args = 3;	break;
			case 301: $function = 'TDIST';			$args = 3;	break;
			case 302: $function = 'WEIBULL';		$args = 4;	break;
			case 303: $function = 'SUMXMY2';		$args = 2;	break;
			case 304: $function = 'SUMX2MY2';		$args = 2;	break;
			case 305: $function = 'SUMX2PY2';		$args = 2;	break;
			case 306: $function = 'CHITEST';		$args = 2;	break;
			case 307: $function = 'CORREL';			$args = 2;	break;
			case 308: $function = 'COVAR';			$args = 2;	break;
			case 309: $function = 'FORECAST';		$args = 3;	break;
			case 310: $function = 'FTEST';			$args = 2;	break;
			case 311: $function = 'INTERCEPT';		$args = 2;	break;
			case 312: $function = 'PEARSON';		$args = 2;	break;
			case 313: $function = 'RSQ';			$args = 2;	break;
			case 314: $function = 'STEYX';			$args = 2;	break;
			case 315: $function = 'SLOPE';			$args = 2;	break;
			case 316: $function = 'TTEST';			$args = 4;	break;
			case 325: $function = 'LARGE';			$args = 2;	break;
			case 326: $function = 'SMALL';			$args = 2;	break;
			case 327: $function = 'QUARTILE';		$args = 2;	break;
			case 328: $function = 'PERCENTILE';		$args = 2;	break;
			case 331: $function = 'TRIMMEAN';		$args = 2;	break;
			case 332: $function = 'TINV';			$args = 2;	break;
			case 337: $function = 'POWER';			$args = 2;	break;
			case 342: $function = 'RADIANS';		$args = 1;	break;
			case 343: $function = 'DEGREES';		$args = 1;	break;
			case 346: $function = 'COUNTIF';		$args = 2;	break;
			case 347: $function = 'COUNTBLANK';		$args = 1;	break;
			case 350: $function = 'ISPMT';			$args = 4;	break;
			case 351: $function = 'DATEDIF';		$args = 3;	break;
			case 352: $function = 'DATESTRING';		$args = 1;	break;
			case 353: $function = 'NUMBERSTRING';	$args = 2;	break;
			case 360: $function = 'PHONETIC';		$args = 1;	break;
			case 368: $function = 'BAHTTEXT';		$args = 1;	break;
			default:
				throw new PHPExcel_Reader_Exception('Unrecognized function in formula');
				break;
			}
			$data = array('function' => $function, 'args' => $args);
			break;
		case 0x22:	//	function with variable number of arguments
		case 0x42:
		case 0x62:
			$name = 'tFuncV';
			$size = 4;
			// offset: 1; size: 1; number of arguments
			$args = ord($formulaData[1]);
			// offset: 2: size: 2; index to built-in sheet function
			$index = self::_GetInt2d($formulaData, 2);
			switch ($index) {
			case   0: $function = 'COUNT';			break;
			case   1: $function = 'IF';				break;
			case   4: $function = 'SUM';			break;
			case   5: $function = 'AVERAGE';		break;
			case   6: $function = 'MIN';			break;
			case   7: $function = 'MAX';			break;
			case   8: $function = 'ROW';			break;
			case   9: $function = 'COLUMN';			break;
			case  11: $function = 'NPV';			break;
			case  12: $function = 'STDEV';			break;
			case  13: $function = 'DOLLAR';			break;
			case  14: $function = 'FIXED';			break;
			case  28: $function = 'LOOKUP';			break;
			case  29: $function = 'INDEX';			break;
			case  36: $function = 'AND';			break;
			case  37: $function = 'OR';				break;
			case  46: $function = 'VAR';			break;
			case  49: $function = 'LINEST';			break;
			case  50: $function = 'TREND';			break;
			case  51: $function = 'LOGEST';			break;
			case  52: $function = 'GROWTH';			break;
			case  56: $function = 'PV';				break;
			case  57: $function = 'FV';				break;
			case  58: $function = 'NPER';			break;
			case  59: $function = 'PMT';			break;
			case  60: $function = 'RATE';			break;
			case  62: $function = 'IRR';			break;
			case  64: $function = 'MATCH';			break;
			case  70: $function = 'WEEKDAY';		break;
			case  78: $function = 'OFFSET';			break;
			case  82: $function = 'SEARCH';			break;
			case 100: $function = 'CHOOSE';			break;
			case 101: $function = 'HLOOKUP';		break;
			case 102: $function = 'VLOOKUP';		break;
			case 109: $function = 'LOG';			break;
			case 115: $function = 'LEFT';			break;
			case 116: $function = 'RIGHT';			break;
			case 120: $function = 'SUBSTITUTE';		break;
			case 124: $function = 'FIND';			break;
			case 125: $function = 'CELL';			break;
			case 144: $function = 'DDB';			break;
			case 148: $function = 'INDIRECT';		break;
			case 167: $function = 'IPMT';			break;
			case 168: $function = 'PPMT';			break;
			case 169: $function = 'COUNTA';			break;
			case 183: $function = 'PRODUCT';		break;
			case 193: $function = 'STDEVP';			break;
			case 194: $function = 'VARP';			break;
			case 197: $function = 'TRUNC';			break;
			case 204: $function = 'USDOLLAR';		break;
			case 205: $function = 'FINDB';			break;
			case 206: $function = 'SEARCHB';		break;
			case 208: $function = 'LEFTB';			break;
			case 209: $function = 'RIGHTB';			break;
			case 216: $function = 'RANK';			break;
			case 219: $function = 'ADDRESS';		break;
			case 220: $function = 'DAYS360';		break;
			case 222: $function = 'VDB';			break;
			case 227: $function = 'MEDIAN';			break;
			case 228: $function = 'SUMPRODUCT';		break;
			case 247: $function = 'DB';				break;
			case 255: $function = '';				break;
			case 269: $function = 'AVEDEV';			break;
			case 270: $function = 'BETADIST';		break;
			case 272: $function = 'BETAINV';		break;
			case 317: $function = 'PROB';			break;
			case 318: $function = 'DEVSQ';			break;
			case 319: $function = 'GEOMEAN';		break;
			case 320: $function = 'HARMEAN';		break;
			case 321: $function = 'SUMSQ';			break;
			case 322: $function = 'KURT';			break;
			case 323: $function = 'SKEW';			break;
			case 324: $function = 'ZTEST';			break;
			case 329: $function = 'PERCENTRANK';	break;
			case 330: $function = 'MODE';			break;
			case 336: $function = 'CONCATENATE';	break;
			case 344: $function = 'SUBTOTAL';		break;
			case 345: $function = 'SUMIF';			break;
			case 354: $function = 'ROMAN';			break;
			case 358: $function = 'GETPIVOTDATA';	break;
			case 359: $function = 'HYPERLINK';		break;
			case 361: $function = 'AVERAGEA';		break;
			case 362: $function = 'MAXA';			break;
			case 363: $function = 'MINA';			break;
			case 364: $function = 'STDEVPA';		break;
			case 365: $function = 'VARPA';			break;
			case 366: $function = 'STDEVA';			break;
			case 367: $function = 'VARA';			break;
			default:
				throw new PHPExcel_Reader_Exception('Unrecognized function in formula');
				break;
			}
			$data = array('function' => $function, 'args' => $args);
			break;
		case 0x23:	//	index to defined name
		case 0x43:
		case 0x63:
			$name = 'tName';
			$size = 5;
			// offset: 1; size: 2; one-based index to definedname record
			$definedNameIndex = self::_GetInt2d($formulaData, 1) - 1;
			// offset: 2; size: 2; not used
			$data = $this->_definedname[$definedNameIndex]['name'];
			break;
		case 0x24:	//	single cell reference e.g. A5
		case 0x44:
		case 0x64:
			$name = 'tRef';
			$size = 5;
			$data = $this->_readBIFF8CellAddress(substr($formulaData, 1, 4));
			break;
		case 0x25:	//	cell range reference to cells in the same sheet (2d)
		case 0x45:
		case 0x65:
			$name = 'tArea';
			$size = 9;
			$data = $this->_readBIFF8CellRangeAddress(substr($formulaData, 1, 8));
			break;
		case 0x26:	//	Constant reference sub-expression
		case 0x46:
		case 0x66:
			$name = 'tMemArea';
			// offset: 1; size: 4; not used
			// offset: 5; size: 2; size of the following subexpression
			$subSize = self::_GetInt2d($formulaData, 5);
			$size = 7 + $subSize;
			$data = $this->_getFormulaFromData(substr($formulaData, 7, $subSize));
			break;
		case 0x27:	//	Deleted constant reference sub-expression
		case 0x47:
		case 0x67:
			$name = 'tMemErr';
			// offset: 1; size: 4; not used
			// offset: 5; size: 2; size of the following subexpression
			$subSize = self::_GetInt2d($formulaData, 5);
			$size = 7 + $subSize;
			$data = $this->_getFormulaFromData(substr($formulaData, 7, $subSize));
			break;
		case 0x29:	//	Variable reference sub-expression
		case 0x49:
		case 0x69:
			$name = 'tMemFunc';
			// offset: 1; size: 2; size of the following sub-expression
			$subSize = self::_GetInt2d($formulaData, 1);
			$size = 3 + $subSize;
			$data = $this->_getFormulaFromData(substr($formulaData, 3, $subSize));
			break;

		case 0x2C: // Relative 2d cell reference reference, used in shared formulas and some other places
		case 0x4C:
		case 0x6C:
			$name = 'tRefN';
			$size = 5;
			$data = $this->_readBIFF8CellAddressB(substr($formulaData, 1, 4), $baseCell);
			break;

		case 0x2D:	//	Relative 2d range reference
		case 0x4D:
		case 0x6D:
			$name = 'tAreaN';
			$size = 9;
			$data = $this->_readBIFF8CellRangeAddressB(substr($formulaData, 1, 8), $baseCell);
			break;

		case 0x39:	//	External name
		case 0x59:
		case 0x79:
			$name = 'tNameX';
			$size = 7;
			// offset: 1; size: 2; index to REF entry in EXTERNSHEET record
			// offset: 3; size: 2; one-based index to DEFINEDNAME or EXTERNNAME record
			$index = self::_GetInt2d($formulaData, 3);
			// assume index is to EXTERNNAME record
			$data = $this->_externalNames[$index - 1]['name'];
			// offset: 5; size: 2; not used
			break;

		case 0x3A:	//	3d reference to cell
		case 0x5A:
		case 0x7A:
			$name = 'tRef3d';
			$size = 7;

			try {
				// offset: 1; size: 2; index to REF entry
				$sheetRange = $this->_readSheetRangeByRefIndex(self::_GetInt2d($formulaData, 1));
				// offset: 3; size: 4; cell address
				$cellAddress = $this->_readBIFF8CellAddress(substr($formulaData, 3, 4));

				$data = "$sheetRange!$cellAddress";
			} catch (PHPExcel_Exception $e) {
				// deleted sheet reference
				$data = '#REF!';
			}

			break;
		case 0x3B:	//	3d reference to cell range
		case 0x5B:
		case 0x7B:
			$name = 'tArea3d';
			$size = 11;

			try {
				// offset: 1; size: 2; index to REF entry
				$sheetRange = $this->_readSheetRangeByRefIndex(self::_GetInt2d($formulaData, 1));
				// offset: 3; size: 8; cell address
				$cellRangeAddress = $this->_readBIFF8CellRangeAddress(substr($formulaData, 3, 8));

				$data = "$sheetRange!$cellRangeAddress";
			} catch (PHPExcel_Exception $e) {
				// deleted sheet reference
				$data = '#REF!';
			}

			break;
		// Unknown cases	// don't know how to deal with
		default:
			throw new PHPExcel_Reader_Exception('Unrecognized token ' . sprintf('%02X', $id) . ' in formula');
			break;
		}

		return array(
			'id' => $id,
			'name' => $name,
			'size' => $size,
			'data' => $data,
		);
	}
356617
public function deleteCacheData($pCoord)
    {
        if ($pCoord === $this->currentObjectID) {
            $this->currentObject->detach();
            $this->currentObjectID = $this->currentObject = null;
        }

        //    Check if the requested entry exists in the cache
        $this->deleteQuery->bindValue('id', $pCoord, SQLITE3_TEXT);
        $result = $this->deleteQuery->execute();
        if ($result === false) {
            throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
        }

        $this->currentCellIsDirty = false;
    }
604396
public function updateNamedFormulas(PHPExcel $pPhpExcel, $oldName = '', $newName = '')
    {
        if ($oldName == '') {
            return;
        }

        foreach ($pPhpExcel->getWorksheetIterator() as $sheet) {
            foreach ($sheet->getCellCollection(false) as $cellID) {
                $cell = $sheet->getCell($cellID);
                if (($cell !== null) && ($cell->getDataType() == PHPExcel_Cell_DataType::TYPE_FORMULA)) {
                    $formula = $cell->getValue();
                    if (strpos($formula, $oldName) !== false) {
                        $formula = str_replace("'" . $oldName . "'!", "'" . $newName . "'!", $formula);
                        $formula = str_replace($oldName . "!", $newName . "!", $formula);
                        $cell->setValueExplicit($formula, PHPExcel_Cell_DataType::TYPE_FORMULA);
                    }
                }
            }
        }
    }
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);
    }
590449
public function getCacheData($pCoord)
    {
        if ($pCoord === $this->currentObjectID) {
            return $this->currentObject;
        }
        $this->storeData();

        $this->selectQuery->bindValue('id', $pCoord, SQLITE3_TEXT);
        $cellResult = $this->selectQuery->execute();
        if ($cellResult === false) {
            throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
        }
        $cellData = $cellResult->fetchArray(SQLITE3_ASSOC);
        if ($cellData === false) {
            //    Return null if requested entry doesn't exist in cache
            return null;
        }

        //    Set current entry to the requested entry
        $this->currentObjectID = $pCoord;

        $this->currentObject = unserialize($cellData['value']);
        //    Re-attach this as the cell's parent
        $this->currentObject->attach($this);

        //    Return requested entry
        return $this->currentObject;
    }
52981
function _convertRange2d($range, $class=0)
	{

		// TODO: possible class value 0,1,2 check Formula.pm
		// Split the range into 2 cell refs
		if (preg_match('/^(\$)?([A-Ia-i]?[A-Za-z])(\$)?(\d+)\:(\$)?([A-Ia-i]?[A-Za-z])(\$)?(\d+)$/', $range)) {
			list($cell1, $cell2) = explode(':', $range);
		} else {
			// TODO: use real error codes
			throw new PHPExcel_Writer_Exception("Unknown range separator");
		}

		// Convert the cell references
		list($row1, $col1) = $this->_cellToPackedRowcol($cell1);
		list($row2, $col2) = $this->_cellToPackedRowcol($cell2);

		// The ptg value depends on the class of the ptg.
		if ($class == 0) {
			$ptgArea = pack("C", $this->ptg['ptgArea']);
		} elseif ($class == 1) {
			$ptgArea = pack("C", $this->ptg['ptgAreaV']);
		} elseif ($class == 2) {
			$ptgArea = pack("C", $this->ptg['ptgAreaA']);
		} else {
			// TODO: use real error codes
			throw new PHPExcel_Writer_Exception("Unknown class $class");
		}
		return $ptgArea . $row1 . $row2 . $col1. $col2;
	}
904743
private static function reverseFormula($formula)
    {
        if (\preg_match('/^n( % \d+)? == \d+(\.\.\d+|,\d+)*?$/', $formula)) {
            return \str_replace(' == ', ' != ', $formula);
        }
        if (\preg_match('/^n( % \d+)? != \d+(\.\.\d+|,\d+)*?$/', $formula)) {
            return \str_replace(' != ', ' == ', $formula);
        }
        if (\preg_match('/^\(?n == \d+ \|\| n == \d+\)?$/', $formula)) {
            return \trim(\str_replace([' == ', ' || '], [' != ', ' && '], $formula), '()');
        }
        $m = null;
        if (\preg_match('/^(n(?: % \d+)?) == (\d+) && (n(?: % \d+)?) != (\d+)$/', $formula, $m)) {
            return "{$m[1]} != {$m[2]} || {$m[3]} == {$m[4]}";
        }
        switch ($formula) {
            case '(n == 1 || n == 2 || n == 3) || n % 10 != 4 && n % 10 != 6 && n % 10 != 9':
                return 'n != 1 && n != 2 && n != 3 && (n % 10 == 4 || n % 10 == 6 || n % 10 == 9)';
            case '(n == 0 || n == 1) || n >= 11 && n <= 99':
                return 'n >= 2 && (n < 11 || n > 99)';
        }
        throw new \InvalidArgumentException("Unable to reverse the formula '$formula'");
    }
979901
private function findCellExpectedAnswer(Cell $cell)
    {
        $best = null;
        foreach ($cell->getChoices() as $choice) {
            /** @var CellChoice $choice */
            if (empty($best) || $best->getScore() < $choice->getScore()) {
                $best = $choice;
            }
        }

        return $best;
    }
1236874
private function _readFormula()
	{
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
		$recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);

		// move stream pointer to next record
		$this->_pos += 4 + $length;

		// offset: 0; size: 2; row index
		$row = self::_GetInt2d($recordData, 0);

		// offset: 2; size: 2; col index
		$column = self::_GetInt2d($recordData, 2);
		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);

		// offset: 20: size: variable; formula structure
		$formulaStructure = substr($recordData, 20);

		// offset: 14: size: 2; option flags, recalculate always, recalculate on open etc.
		$options = self::_GetInt2d($recordData, 14);

		// bit: 0; mask: 0x0001; 1 = recalculate always
		// bit: 1; mask: 0x0002; 1 = calculate on open
		// bit: 2; mask: 0x0008; 1 = part of a shared formula
		$isPartOfSharedFormula = (bool) (0x0008 & $options);

		// WARNING:
		// We can apparently not rely on $isPartOfSharedFormula. Even when $isPartOfSharedFormula = true
		// the formula data may be ordinary formula data, therefore we need to check
		// explicitly for the tExp token (0x01)
		$isPartOfSharedFormula = $isPartOfSharedFormula && ord($formulaStructure{2}) == 0x01;

		if ($isPartOfSharedFormula) {
			// part of shared formula which means there will be a formula with a tExp token and nothing else
			// get the base cell, grab tExp token
			$baseRow = self::_GetInt2d($formulaStructure, 3);
			$baseCol = self::_GetInt2d($formulaStructure, 5);
			$this->_baseCell = PHPExcel_Cell::stringFromColumnIndex($baseCol). ($baseRow + 1);
		}

		// Read cell?
		if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {

			if ($isPartOfSharedFormula) {
				// formula is added to this cell after the sheet has been read
				$this->_sharedFormulaParts[$columnString . ($row + 1)] = $this->_baseCell;
			}

			// offset: 16: size: 4; not used

			// offset: 4; size: 2; XF index
			$xfIndex = self::_GetInt2d($recordData, 4);

			// offset: 6; size: 8; result of the formula
			if ( (ord($recordData{6}) == 0)
				&& (ord($recordData{12}) == 255)
				&& (ord($recordData{13}) == 255) ) {

				// String formula. Result follows in appended STRING record
				$dataType = PHPExcel_Cell_DataType::TYPE_STRING;

				// read possible SHAREDFMLA record
				$code = self::_GetInt2d($this->_data, $this->_pos);
				if ($code == self::XLS_Type_SHAREDFMLA) {
					$this->_readSharedFmla();
				}

				// read STRING record
				$value = $this->_readString();

			} elseif ((ord($recordData{6}) == 1)
				&& (ord($recordData{12}) == 255)
				&& (ord($recordData{13}) == 255)) {

				// Boolean formula. Result is in +2; 0=false, 1=true
				$dataType = PHPExcel_Cell_DataType::TYPE_BOOL;
				$value = (bool) ord($recordData{8});

			} elseif ((ord($recordData{6}) == 2)
				&& (ord($recordData{12}) == 255)
				&& (ord($recordData{13}) == 255)) {

				// Error formula. Error code is in +2
				$dataType = PHPExcel_Cell_DataType::TYPE_ERROR;
				$value = self::_mapErrorCode(ord($recordData{8}));

			} elseif ((ord($recordData{6}) == 3)
				&& (ord($recordData{12}) == 255)
				&& (ord($recordData{13}) == 255)) {

				// Formula result is a null string
				$dataType = PHPExcel_Cell_DataType::TYPE_NULL;
				$value = '';

			} else {

				// forumla result is a number, first 14 bytes like _NUMBER record
				$dataType = PHPExcel_Cell_DataType::TYPE_NUMERIC;
				$value = self::_extractNumber(substr($recordData, 6, 8));

			}

			$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
			if (!$this->_readDataOnly) {
				// add cell style
				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
			}

			// store the formula
			if (!$isPartOfSharedFormula) {
				// not part of shared formula
				// add cell value. If we can read formula, populate with formula, otherwise just used cached value
				try {
					if ($this->_version != self::XLS_BIFF8) {
						throw new PHPExcel_Reader_Exception('Not BIFF8. Can only read BIFF8 formulas');
					}
					$formula = $this->_getFormulaFromStructure($formulaStructure); // get formula in human language
					$cell->setValueExplicit('=' . $formula, PHPExcel_Cell_DataType::TYPE_FORMULA);

				} catch (PHPExcel_Exception $e) {
					$cell->setValueExplicit($value, $dataType);
				}
			} else {
				if ($this->_version == self::XLS_BIFF8) {
					// do nothing at this point, formula id added later in the code
				} else {
					$cell->setValueExplicit($value, $dataType);
				}
			}

			// store the cached calculated value
			$cell->setCalculatedValue($value);
		}
	}
687264
public function setColumn($pColumn)
    {
        if ((is_string($pColumn)) && (!empty($pColumn))) {
            $column = $pColumn;
        } elseif (is_object($pColumn) && ($pColumn instanceof PHPExcel_Worksheet_AutoFilter_Column)) {
            $column = $pColumn->getColumnIndex();
        } else {
            throw new PHPExcel_Exception("Column is not within the autofilter range.");
        }
        $this->testColumnInRange($column);

        if (is_string($pColumn)) {
            $this->columns[$pColumn] = new PHPExcel_Worksheet_AutoFilter_Column($pColumn, $this);
        } elseif (is_object($pColumn) && ($pColumn instanceof PHPExcel_Worksheet_AutoFilter_Column)) {
            $pColumn->setParent($this);
            $this->columns[$column] = $pColumn;
        }
        ksort($this->columns);

        return $this;
    }
262045
public function getToken($pId = 0)
    {
        if (isset($this->tokens[$pId])) {
            return $this->tokens[$pId];
        } else {
            throw new PHPExcel_Calculation_Exception("Token with id $pId does not exist.");
        }
    }
918437
public function isDataSet($pCoord) {
        //    Check if the requested entry is the current object, or exists in the cache
        if (parent::isDataSet($pCoord)) {
            if ($this->_currentObjectID == $pCoord) {
                return true;
            }
            //    Check if the requested entry still exists in apc
            $success = apc_fetch($this->_cachePrefix.$pCoord.'.cache');
            if ($success === FALSE) {
                //    Entry no longer exists in APC, so clear it from the cache array
                parent::deleteCacheData($pCoord);
                throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in APC cache');
            }
            return true;
        }
        return false;
    }
367731
private static Object getCellValue(Cell cell) throws Exception {
        Object value = null;
        if (cell instanceof ErrorCell) {
            value = null;
        } else if (cell instanceof LabelCell) {
            value = ((LabelCell) cell).getString();
        } else if (cell instanceof NumberCell) {
            value = ((NumberCell) cell).getValue();
        } else if (cell instanceof DateCell) {
            value = ((DateCell) cell).getDate();
        } else if (cell instanceof BooleanCell) {
            value = ((BooleanCell) cell).getValue();
        } /*else if (cell instanceof FormulaCell) {
            value = ((FormulaCell) cell).getFormula();
        }*/ else {
            value = cell.getContents();
        }
        return value;
    }
342088
public function getResult()
    {
        // Check that the formula is not empty
        if (!isset($this->formula[0])) {
            $this->correct = 0;
            $this->error_type = 2;
        }

        // Check set variables
        for ($i=0; $i<=count($this->valid_variables)-1; $i++) { 
            if (strlen($this->valid_variables[$i]) != 1  
            || !preg_match('/^([a-z])$/', $this->valid_variables[$i]) === 1
            || $this->valid_variables[$i] == "e") {
                $this->correct = 0;
                $this->error_type = 4;
            }
        }

        $this->prepare($this->formula);
        $this->group($this->formula);

        $open_parentheses_count = substr_count($this->formula, '(');
        $close_parentheses_count = substr_count($this->formula, ')');

        // Check for an equality of opening and closing parentheses
        if ($open_parentheses_count != $close_parentheses_count) {
            $this->correct = 0;
            $this->error_type = 3;
        }

        // Check the syntax is correct when using parentheses
        if (preg_match('/(\)( )?[^\)\+\-\*\/\^ ])|(\(( )*?\))|([^nstgp\(\+\-\*\/\^ ]( )?\()/',
        $this->formula)) {
            $this->correct = 0;
        }

        $processing_formula = $this->formula;

        // Begin a general parse
        while ((strstr($processing_formula, '(') || strstr($processing_formula, ')'))
        && $this->correct) {
            $start_cursor_pos = 0; $end_cursor_pos = 0;
            $this->group($processing_formula, '');
            $temp = $processing_formula;

            while (strstr($temp, '(')) {
                $strlen_temp = strlen($temp);
                for ($i=0; $i<=$strlen_temp-1; $i++) {
                    if (isset($temp[$i]) && $temp[$i] == '(') {
                        $temp = substr($temp, $i+1);
                        $start_cursor_pos = $start_cursor_pos + $i+1;
                    }
                }
            }

            $strlen_temp = strlen($temp);
            for ($i=0; $i<=$strlen_temp-1; $i++) {
                if (isset($temp[$i]) && $temp[$i] == ')') {
                    $end_cursor_pos = $strlen_temp - $i;
                    $temp = substr($temp, 0, $i);
                    break;
                }
            }

            $length = strlen($processing_formula);

            if (!empty($temp)) {
                $temp = $this->parse($temp);
                $checkExp = $this->checkExp($processing_formula, $length, $end_cursor_pos, $temp);
                if (isset($checkExp->result)) {
                    $temp = $checkExp->result;
                    $end_cursor_pos = $checkExp->cursor;
                }
            }

            $processing_formula = substr($processing_formula, 0, $start_cursor_pos-1)
                    .$temp.substr($processing_formula, $length - $end_cursor_pos+1);
        }

        $this->formula = $processing_formula;

        $result = $this->parse($this->formula);

        if ($this->correct) {
            return ['done', $this->round_($result, $this->precision)];
        } else {
            return ['error', $this->errorMsg()];
        }
    }
424101
public function calculate($expression) {
        // Make sure no malicious code is present in the expression. Refer MDL-46148 for details.
        if ($error = qtype_calculated_find_formula_errors($expression)) {
            throw new moodle_exception('illegalformulasyntax', 'qtype_calculated', '', $error);
        }
        $expression = $this->substitute_values_for_eval($expression);
        if ($datasets = question_bank::get_qtype('calculated')->find_dataset_names($expression)) {
            // Some placeholders were not substituted.
            throw new moodle_exception('illegalformulasyntax', 'qtype_calculated', '',
                '{' . reset($datasets) . '}');
        }
        return $this->calculate_raw($expression);
    }
614805
public static function coordinateFromString($pCoordinateString = 'A1')
	{
		if (preg_match("/^([$]?[A-Z]{1,3})([$]?\d{1,7})$/", $pCoordinateString, $matches)) {
			return array($matches[1],$matches[2]);
		} elseif ((strpos($pCoordinateString,':') !== FALSE) || (strpos($pCoordinateString,',') !== FALSE)) {
			throw new PHPExcel_Exception('Cell coordinate string can not be a range of cells');
		} elseif ($pCoordinateString == '') {
			throw new PHPExcel_Exception('Cell coordinate can not be zero-length string');
		}

		throw new PHPExcel_Exception('Invalid cell coordinate '.$pCoordinateString);
	}