ILIAS  Release_4_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
Calculation.php
Go to the documentation of this file.
1 <?php
30 if (!defined('PHPEXCEL_ROOT')) {
34  define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../');
35 }
36 
38 require_once PHPEXCEL_ROOT . 'PHPExcel/Shared/JAMA/Matrix.php';
39 
41 require_once PHPEXCEL_ROOT . 'PHPExcel/Calculation/Function.php';
42 
44 require_once PHPEXCEL_ROOT . 'PHPExcel/Calculation/Functions.php';
45 
46 
55 
58  // Numeric operand
59  const CALCULATION_REGEXP_NUMBER = '[-+]?\d*\.?\d+(e[-+]?\d+)?';
60  // String operand
61  const CALCULATION_REGEXP_STRING = '"(?:[^"]|"")*"';
62  // Opening bracket
64  // Function
65  const CALCULATION_REGEXP_FUNCTION = '([A-Z][A-Z0-9\.]*)[\s]*\(';
66  // Cell reference (cell or range of cells, with or without a sheet reference)
67  const CALCULATION_REGEXP_CELLREF = '(((\w*)|(\'.*\')|(\".*\"))!)?\$?([a-z]+)\$?(\d+)(:\$?([a-z]+)\$?(\d+))?';
68  // Named Range of cells
69  const CALCULATION_REGEXP_NAMEDRANGE = '(((\w*)|(\'.*\')|(\".*\"))!)?([_A-Z][_A-Z0-9]*)';
70  // Error
71  const CALCULATION_REGEXP_ERROR = '\#[^!]+!';
72 
73 
75  const RETURN_ARRAY_AS_VALUE = 'value';
76  const RETURN_ARRAY_AS_ARRAY = 'array';
77 
79 
86  private static $_instance;
87 
88 
95  private $_calculationCache = array ();
96 
97 
105 
106 
114 
115 
122  private $_operators = array('+', '-', '*', '/', '^', '&', '%', '_', '>', '<', '=', '>=', '<=', '<>');
123 
124 
131  private $_binaryOperators = array('+', '-', '*', '/', '^', '&', '>', '<', '=', '>=', '<=', '<>');
132 
133  public $suppressFormulaErrors = false;
134  public $formulaError = null;
135  public $writeDebugLog = false;
136  private $debugLogStack = array();
137  public $debugLog = array();
138 
139 
140  // Constant conversion from text name/value to actual (datatyped) value
141  private $_ExcelConstants = array('TRUE' => True,
142  'FALSE' => False,
143  'NULL' => Null
144  );
145 
146  // PHPExcel functions
147  private $_PHPExcelFunctions = array( // PHPExcel functions
148  'ABS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
149  'functionCall' => 'abs',
150  'argumentCount' => '1'
151  ),
152  'ACCRINT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
153  'functionCall' => 'PHPExcel_Calculation_Functions::ACCRINT',
154  'argumentCount' => '4-7'
155  ),
156  'ACCRINTM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
157  'functionCall' => 'PHPExcel_Calculation_Functions::ACCRINTM',
158  'argumentCount' => '3-5'
159  ),
160  'ACOS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
161  'functionCall' => 'acos',
162  'argumentCount' => '1'
163  ),
164  'ACOSH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
165  'functionCall' => 'acosh',
166  'argumentCount' => '1'
167  ),
168  'ADDRESS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
169  'functionCall' => 'PHPExcel_Calculation_Functions::CELL_ADDRESS',
170  'argumentCount' => '2-5'
171  ),
172  'AMORDEGRC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
173  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
174  'argumentCount' => '6,7'
175  ),
176  'AMORLINC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
177  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
178  'argumentCount' => '6,7'
179  ),
180  'AND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
181  'functionCall' => 'PHPExcel_Calculation_Functions::LOGICAL_AND',
182  'argumentCount' => '1+'
183  ),
185  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
186  'argumentCount' => '1'
187  ),
188  'ASC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
189  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
190  'argumentCount' => '1'
191  ),
192  'ASIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
193  'functionCall' => 'asin',
194  'argumentCount' => '1'
195  ),
196  'ASINH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
197  'functionCall' => 'asinh',
198  'argumentCount' => '1'
199  ),
200  'ATAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
201  'functionCall' => 'atan',
202  'argumentCount' => '1'
203  ),
204  'ATAN2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
205  'functionCall' => 'PHPExcel_Calculation_Functions::REVERSE_ATAN2',
206  'argumentCount' => '2'
207  ),
208  'ATANH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
209  'functionCall' => 'atanh',
210  'argumentCount' => '1'
211  ),
212  'AVEDEV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
213  'functionCall' => 'PHPExcel_Calculation_Functions::AVEDEV',
214  'argumentCount' => '1+'
215  ),
216  'AVERAGE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
217  'functionCall' => 'PHPExcel_Calculation_Functions::AVERAGE',
218  'argumentCount' => '1+'
219  ),
220  'AVERAGEA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
221  'functionCall' => 'PHPExcel_Calculation_Functions::AVERAGEA',
222  'argumentCount' => '1+'
223  ),
224  'AVERAGEIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
225  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
226  'argumentCount' => '2,3'
227  ),
228  'AVERAGEIFS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
229  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
230  'argumentCount' => '3+'
231  ),
232  'BAHTTEXT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
233  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
234  'argumentCount' => '1'
235  ),
236  'BESSELI' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
237  'functionCall' => 'PHPExcel_Calculation_Functions::BESSELI',
238  'argumentCount' => '2'
239  ),
240  'BESSELJ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
241  'functionCall' => 'PHPExcel_Calculation_Functions::BESSELJ',
242  'argumentCount' => '2'
243  ),
244  'BESSELK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
245  'functionCall' => 'PHPExcel_Calculation_Functions::BESSELK',
246  'argumentCount' => '2'
247  ),
248  'BESSELY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
249  'functionCall' => 'PHPExcel_Calculation_Functions::BESSELY',
250  'argumentCount' => '2'
251  ),
252  'BETADIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
253  'functionCall' => 'PHPExcel_Calculation_Functions::BETADIST',
254  'argumentCount' => '3-5'
255  ),
256  'BETAINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
257  'functionCall' => 'PHPExcel_Calculation_Functions::BETAINV',
258  'argumentCount' => '3-5'
259  ),
260  'BIN2DEC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
261  'functionCall' => 'PHPExcel_Calculation_Functions::BINTODEC',
262  'argumentCount' => '1'
263  ),
264  'BIN2HEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
265  'functionCall' => 'PHPExcel_Calculation_Functions::BINTOHEX',
266  'argumentCount' => '1,2'
267  ),
268  'BIN2OCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
269  'functionCall' => 'PHPExcel_Calculation_Functions::BINTOOCT',
270  'argumentCount' => '1,2'
271  ),
272  'BINOMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
273  'functionCall' => 'PHPExcel_Calculation_Functions::BINOMDIST',
274  'argumentCount' => '4'
275  ),
276  'CEILING' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
277  'functionCall' => 'PHPExcel_Calculation_Functions::CEILING',
278  'argumentCount' => '2'
279  ),
280  'CELL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
281  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
282  'argumentCount' => '1,2'
283  ),
284  'CHAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
285  'functionCall' => 'PHPExcel_Calculation_Functions::CHARACTER',
286  'argumentCount' => '1'
287  ),
288  'CHIDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
289  'functionCall' => 'PHPExcel_Calculation_Functions::CHIDIST',
290  'argumentCount' => '2'
291  ),
292  'CHIINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
293  'functionCall' => 'PHPExcel_Calculation_Functions::CHIINV',
294  'argumentCount' => '2'
295  ),
296  'CHITEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
297  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
298  'argumentCount' => '2'
299  ),
300  'CHOOSE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
301  'functionCall' => 'PHPExcel_Calculation_Functions::CHOOSE',
302  'argumentCount' => '2+'
303  ),
304  'CLEAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
305  'functionCall' => 'PHPExcel_Calculation_Functions::TRIMNONPRINTABLE',
306  'argumentCount' => '1'
307  ),
308  'CODE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
309  'functionCall' => 'PHPExcel_Calculation_Functions::ASCIICODE',
310  'argumentCount' => '1'
311  ),
312  'COLUMN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
313  'functionCall' => 'PHPExcel_Calculation_Functions::COLUMN',
314  'argumentCount' => '-1'
315  ),
316  'COLUMNS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
317  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
318  'argumentCount' => '1'
319  ),
320  'COMBIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
321  'functionCall' => 'PHPExcel_Calculation_Functions::COMBIN',
322  'argumentCount' => '2'
323  ),
324  'COMPLEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
325  'functionCall' => 'PHPExcel_Calculation_Functions::COMPLEX',
326  'argumentCount' => '2,3'
327  ),
328  'CONCATENATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
329  'functionCall' => 'PHPExcel_Calculation_Functions::CONCATENATE',
330  'argumentCount' => '1+'
331  ),
332  'CONFIDENCE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
333  'functionCall' => 'PHPExcel_Calculation_Functions::CONFIDENCE',
334  'argumentCount' => '3'
335  ),
336  'CONVERT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
337  'functionCall' => 'PHPExcel_Calculation_Functions::CONVERTUOM',
338  'argumentCount' => '3'
339  ),
340  'CORREL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
341  'functionCall' => 'PHPExcel_Calculation_Functions::CORREL',
342  'argumentCount' => '2'
343  ),
344  'COS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
345  'functionCall' => 'cos',
346  'argumentCount' => '1'
347  ),
348  'COSH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
349  'functionCall' => 'cosh',
350  'argumentCount' => '1'
351  ),
352  'COUNT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
353  'functionCall' => 'PHPExcel_Calculation_Functions::COUNT',
354  'argumentCount' => '1+'
355  ),
356  'COUNTA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
357  'functionCall' => 'PHPExcel_Calculation_Functions::COUNTA',
358  'argumentCount' => '1+'
359  ),
360  'COUNTBLANK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
361  'functionCall' => 'PHPExcel_Calculation_Functions::COUNTBLANK',
362  'argumentCount' => '1'
363  ),
364  'COUNTIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
365  'functionCall' => 'PHPExcel_Calculation_Functions::COUNTIF',
366  'argumentCount' => '2'
367  ),
368  'COUNTIFS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
369  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
370  'argumentCount' => '2'
371  ),
372  'COUPDAYBS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
373  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
374  'argumentCount' => '3,4'
375  ),
376  'COUPDAYS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
377  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
378  'argumentCount' => '3,4'
379  ),
380  'COUPDAYSNC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
381  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
382  'argumentCount' => '3,4'
383  ),
384  'COUPNCD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
385  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
386  'argumentCount' => '3,4'
387  ),
388  'COUPNUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
389  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
390  'argumentCount' => '3,4'
391  ),
392  'COUPPCD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
393  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
394  'argumentCount' => '3,4'
395  ),
396  'COVAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
397  'functionCall' => 'PHPExcel_Calculation_Functions::COVAR',
398  'argumentCount' => '2'
399  ),
400  'CRITBINOM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
401  'functionCall' => 'PHPExcel_Calculation_Functions::CRITBINOM',
402  'argumentCount' => '3'
403  ),
404  'CUBEKPIMEMBER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
405  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
406  'argumentCount' => '?'
407  ),
408  'CUBEMEMBER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
409  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
410  'argumentCount' => '?'
411  ),
412  'CUBEMEMBERPROPERTY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
413  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
414  'argumentCount' => '?'
415  ),
416  'CUBERANKEDMEMBER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
417  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
418  'argumentCount' => '?'
419  ),
420  'CUBESET' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
421  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
422  'argumentCount' => '?'
423  ),
424  'CUBESETCOUNT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
425  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
426  'argumentCount' => '?'
427  ),
428  'CUBEVALUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
429  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
430  'argumentCount' => '?'
431  ),
432  'CUMIPMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
433  'functionCall' => 'PHPExcel_Calculation_Functions::CUMIPMT',
434  'argumentCount' => '6'
435  ),
436  'CUMPRINC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
437  'functionCall' => 'PHPExcel_Calculation_Functions::CUMPRINC',
438  'argumentCount' => '6'
439  ),
440  'DATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
441  'functionCall' => 'PHPExcel_Calculation_Functions::DATE',
442  'argumentCount' => '3'
443  ),
444  'DATEDIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
445  'functionCall' => 'PHPExcel_Calculation_Functions::DATEDIF',
446  'argumentCount' => '3'
447  ),
448  'DATEVALUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
449  'functionCall' => 'PHPExcel_Calculation_Functions::DATEVALUE',
450  'argumentCount' => '1'
451  ),
452  'DAVERAGE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
453  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
454  'argumentCount' => '?'
455  ),
456  'DAY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
457  'functionCall' => 'PHPExcel_Calculation_Functions::DAYOFMONTH',
458  'argumentCount' => '1'
459  ),
460  'DAYS360' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
461  'functionCall' => 'PHPExcel_Calculation_Functions::DAYS360',
462  'argumentCount' => '2,3'
463  ),
464  'DB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
465  'functionCall' => 'PHPExcel_Calculation_Functions::DB',
466  'argumentCount' => '4,5'
467  ),
468  'DCOUNT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
469  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
470  'argumentCount' => '?'
471  ),
472  'DCOUNTA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
473  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
474  'argumentCount' => '?'
475  ),
476  'DDB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
477  'functionCall' => 'PHPExcel_Calculation_Functions::DDB',
478  'argumentCount' => '4,5'
479  ),
480  'DEC2BIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
481  'functionCall' => 'PHPExcel_Calculation_Functions::DECTOBIN',
482  'argumentCount' => '1,2'
483  ),
484  'DEC2HEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
485  'functionCall' => 'PHPExcel_Calculation_Functions::DECTOHEX',
486  'argumentCount' => '1,2'
487  ),
488  'DEC2OCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
489  'functionCall' => 'PHPExcel_Calculation_Functions::DECTOOCT',
490  'argumentCount' => '1,2'
491  ),
492  'DEGREES' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
493  'functionCall' => 'rad2deg',
494  'argumentCount' => '1'
495  ),
496  'DELTA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
497  'functionCall' => 'PHPExcel_Calculation_Functions::DELTA',
498  'argumentCount' => '1,2'
499  ),
500  'DEVSQ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
501  'functionCall' => 'PHPExcel_Calculation_Functions::DEVSQ',
502  'argumentCount' => '1+'
503  ),
504  'DGET' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
505  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
506  'argumentCount' => '?'
507  ),
508  'DISC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
509  'functionCall' => 'PHPExcel_Calculation_Functions::DISC',
510  'argumentCount' => '4,5'
511  ),
512  'DMAX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
513  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
514  'argumentCount' => '?'
515  ),
516  'DMIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
517  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
518  'argumentCount' => '?'
519  ),
520  'DOLLAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
521  'functionCall' => 'PHPExcel_Calculation_Functions::DOLLAR',
522  'argumentCount' => '1,2'
523  ),
524  'DOLLARDE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
525  'functionCall' => 'PHPExcel_Calculation_Functions::DOLLARDE',
526  'argumentCount' => '2'
527  ),
528  'DOLLARFR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
529  'functionCall' => 'PHPExcel_Calculation_Functions::DOLLARFR',
530  'argumentCount' => '2'
531  ),
532  'DPRODUCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
533  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
534  'argumentCount' => '?'
535  ),
536  'DSTDEV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
537  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
538  'argumentCount' => '?'
539  ),
540  'DSTDEVP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
541  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
542  'argumentCount' => '?'
543  ),
544  'DSUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
545  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
546  'argumentCount' => '?'
547  ),
548  'DURATION' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
549  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
550  'argumentCount' => '5,6'
551  ),
552  'DVAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
553  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
554  'argumentCount' => '?'
555  ),
556  'DVARP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
557  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
558  'argumentCount' => '?'
559  ),
560  'EDATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
561  'functionCall' => 'PHPExcel_Calculation_Functions::EDATE',
562  'argumentCount' => '2'
563  ),
564  'EFFECT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
565  'functionCall' => 'PHPExcel_Calculation_Functions::EFFECT',
566  'argumentCount' => '2'
567  ),
568  'EOMONTH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
569  'functionCall' => 'PHPExcel_Calculation_Functions::EOMONTH',
570  'argumentCount' => '2'
571  ),
572  'ERF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
573  'functionCall' => 'PHPExcel_Calculation_Functions::ERF',
574  'argumentCount' => '1,2'
575  ),
576  'ERFC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
577  'functionCall' => 'PHPExcel_Calculation_Functions::ERFC',
578  'argumentCount' => '1'
579  ),
580  'ERROR.TYPE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
581  'functionCall' => 'PHPExcel_Calculation_Functions::ERROR_TYPE',
582  'argumentCount' => '1'
583  ),
584  'EVEN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
585  'functionCall' => 'PHPExcel_Calculation_Functions::EVEN',
586  'argumentCount' => '1'
587  ),
588  'EXACT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
589  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
590  'argumentCount' => '2'
591  ),
592  'EXP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
593  'functionCall' => 'exp',
594  'argumentCount' => '1'
595  ),
596  'EXPONDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
597  'functionCall' => 'PHPExcel_Calculation_Functions::EXPONDIST',
598  'argumentCount' => '3'
599  ),
600  'FACT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
601  'functionCall' => 'PHPExcel_Calculation_Functions::FACT',
602  'argumentCount' => '1'
603  ),
604  'FACTDOUBLE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
605  'functionCall' => 'PHPExcel_Calculation_Functions::FACTDOUBLE',
606  'argumentCount' => '1'
607  ),
608  'FALSE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
609  'functionCall' => 'PHPExcel_Calculation_Functions::LOGICAL_FALSE',
610  'argumentCount' => '0'
611  ),
612  'FDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
613  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
614  'argumentCount' => '3'
615  ),
616  'FIND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
617  'functionCall' => 'PHPExcel_Calculation_Functions::SEARCHSENSITIVE',
618  'argumentCount' => '2,3'
619  ),
620  'FINDB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
621  'functionCall' => 'PHPExcel_Calculation_Functions::SEARCHSENSITIVE',
622  'argumentCount' => '2,3'
623  ),
624  'FINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
625  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
626  'argumentCount' => '3'
627  ),
628  'FISHER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
629  'functionCall' => 'PHPExcel_Calculation_Functions::FISHER',
630  'argumentCount' => '1'
631  ),
632  'FISHERINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
633  'functionCall' => 'PHPExcel_Calculation_Functions::FISHERINV',
634  'argumentCount' => '1'
635  ),
636  'FIXED' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
637  'functionCall' => 'PHPExcel_Calculation_Functions::FIXEDFORMAT',
638  'argumentCount' => '1-3'
639  ),
640  'FLOOR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
641  'functionCall' => 'PHPExcel_Calculation_Functions::FLOOR',
642  'argumentCount' => '2'
643  ),
644  'FORECAST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
645  'functionCall' => 'PHPExcel_Calculation_Functions::FORECAST',
646  'argumentCount' => '3'
647  ),
648  'FREQUENCY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
649  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
650  'argumentCount' => '2'
651  ),
652  'FTEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
653  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
654  'argumentCount' => '2'
655  ),
656  'FV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
657  'functionCall' => 'PHPExcel_Calculation_Functions::FV',
658  'argumentCount' => '3-5'
659  ),
660  'FVSCHEDULE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
661  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
662  'argumentCount' => '2'
663  ),
664  'GAMMADIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
665  'functionCall' => 'PHPExcel_Calculation_Functions::GAMMADIST',
666  'argumentCount' => '4'
667  ),
668  'GAMMAINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
669  'functionCall' => 'PHPExcel_Calculation_Functions::GAMMAINV',
670  'argumentCount' => '3'
671  ),
672  'GAMMALN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
673  'functionCall' => 'PHPExcel_Calculation_Functions::GAMMALN',
674  'argumentCount' => '1'
675  ),
676  'GCD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
677  'functionCall' => 'PHPExcel_Calculation_Functions::GCD',
678  'argumentCount' => '1+'
679  ),
680  'GEOMEAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
681  'functionCall' => 'PHPExcel_Calculation_Functions::GEOMEAN',
682  'argumentCount' => '1+'
683  ),
684  'GESTEP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
685  'functionCall' => 'PHPExcel_Calculation_Functions::GESTEP',
686  'argumentCount' => '1,2'
687  ),
688  'GETPIVOTDATA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
689  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
690  'argumentCount' => '2+'
691  ),
692  'GROWTH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
693  'functionCall' => 'PHPExcel_Calculation_Functions::GROWTH',
694  'argumentCount' => '1-4'
695  ),
696  'HARMEAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
697  'functionCall' => 'PHPExcel_Calculation_Functions::HARMEAN',
698  'argumentCount' => '1+'
699  ),
700  'HEX2BIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
701  'functionCall' => 'PHPExcel_Calculation_Functions::HEXTOBIN',
702  'argumentCount' => '1,2'
703  ),
704  'HEX2DEC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
705  'functionCall' => 'PHPExcel_Calculation_Functions::HEXTODEC',
706  'argumentCount' => '1'
707  ),
708  'HEX2OCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
709  'functionCall' => 'PHPExcel_Calculation_Functions::HEXTOOCT',
710  'argumentCount' => '1,2'
711  ),
712  'HLOOKUP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
713  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
714  'argumentCount' => '3,4'
715  ),
716  'HOUR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
717  'functionCall' => 'PHPExcel_Calculation_Functions::HOUROFDAY',
718  'argumentCount' => '1'
719  ),
720  'HYPERLINK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
721  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
722  'argumentCount' => '1,2'
723  ),
724  'HYPGEOMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
725  'functionCall' => 'PHPExcel_Calculation_Functions::HYPGEOMDIST',
726  'argumentCount' => '4'
727  ),
728  'IF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
729  'functionCall' => 'PHPExcel_Calculation_Functions::STATEMENT_IF',
730  'argumentCount' => '1-3'
731  ),
732  'IFERROR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
733  'functionCall' => 'PHPExcel_Calculation_Functions::STATEMENT_IFERROR',
734  'argumentCount' => '1'
735  ),
736  'IMABS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
737  'functionCall' => 'PHPExcel_Calculation_Functions::IMABS',
738  'argumentCount' => '1'
739  ),
740  'IMAGINARY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
741  'functionCall' => 'PHPExcel_Calculation_Functions::IMAGINARY',
742  'argumentCount' => '1'
743  ),
744  'IMARGUMENT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
745  'functionCall' => 'PHPExcel_Calculation_Functions::IMARGUMENT',
746  'argumentCount' => '1'
747  ),
748  'IMCONJUGATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
749  'functionCall' => 'PHPExcel_Calculation_Functions::IMCONJUGATE',
750  'argumentCount' => '1'
751  ),
752  'IMCOS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
753  'functionCall' => 'PHPExcel_Calculation_Functions::IMCOS',
754  'argumentCount' => '1'
755  ),
756  'IMDIV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
757  'functionCall' => 'PHPExcel_Calculation_Functions::IMDIV',
758  'argumentCount' => '2'
759  ),
760  'IMEXP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
761  'functionCall' => 'PHPExcel_Calculation_Functions::IMEXP',
762  'argumentCount' => '1'
763  ),
764  'IMLN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
765  'functionCall' => 'PHPExcel_Calculation_Functions::IMLN',
766  'argumentCount' => '1'
767  ),
768  'IMLOG10' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
769  'functionCall' => 'PHPExcel_Calculation_Functions::IMLOG10',
770  'argumentCount' => '1'
771  ),
772  'IMLOG2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
773  'functionCall' => 'PHPExcel_Calculation_Functions::IMLOG2',
774  'argumentCount' => '1'
775  ),
776  'IMPOWER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
777  'functionCall' => 'PHPExcel_Calculation_Functions::IMPOWER',
778  'argumentCount' => '2'
779  ),
780  'IMPRODUCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
781  'functionCall' => 'PHPExcel_Calculation_Functions::IMPRODUCT',
782  'argumentCount' => '1+'
783  ),
784  'IMREAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
785  'functionCall' => 'PHPExcel_Calculation_Functions::IMREAL',
786  'argumentCount' => '1'
787  ),
788  'IMSIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
789  'functionCall' => 'PHPExcel_Calculation_Functions::IMSIN',
790  'argumentCount' => '1'
791  ),
792  'IMSQRT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
793  'functionCall' => 'PHPExcel_Calculation_Functions::IMSQRT',
794  'argumentCount' => '1'
795  ),
796  'IMSUB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
797  'functionCall' => 'PHPExcel_Calculation_Functions::IMSUB',
798  'argumentCount' => '2'
799  ),
800  'IMSUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
801  'functionCall' => 'PHPExcel_Calculation_Functions::IMSUM',
802  'argumentCount' => '1+'
803  ),
805  'functionCall' => 'PHPExcel_Calculation_Functions::INDEX',
806  'argumentCount' => '1-4'
807  ),
808  'INDIRECT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
809  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
810  'argumentCount' => '1,2'
811  ),
812  'INFO' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
813  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
814  'argumentCount' => '1'
815  ),
816  'INT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
817  'functionCall' => 'PHPExcel_Calculation_Functions::INTVALUE',
818  'argumentCount' => '1'
819  ),
820  'INTERCEPT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
821  'functionCall' => 'PHPExcel_Calculation_Functions::INTERCEPT',
822  'argumentCount' => '2'
823  ),
824  'INTRATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
825  'functionCall' => 'PHPExcel_Calculation_Functions::INTRATE',
826  'argumentCount' => '4,5'
827  ),
828  'IPMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
829  'functionCall' => 'PHPExcel_Calculation_Functions::IPMT',
830  'argumentCount' => '4-6'
831  ),
832  'IRR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
833  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
834  'argumentCount' => '1,2'
835  ),
836  'ISBLANK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
837  'functionCall' => 'PHPExcel_Calculation_Functions::IS_BLANK',
838  'argumentCount' => '1'
839  ),
840  'ISERR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
841  'functionCall' => 'PHPExcel_Calculation_Functions::IS_ERR',
842  'argumentCount' => '1'
843  ),
844  'ISERROR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
845  'functionCall' => 'PHPExcel_Calculation_Functions::IS_ERROR',
846  'argumentCount' => '1'
847  ),
848  'ISEVEN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
849  'functionCall' => 'PHPExcel_Calculation_Functions::IS_EVEN',
850  'argumentCount' => '1'
851  ),
852  'ISLOGICAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
853  'functionCall' => 'PHPExcel_Calculation_Functions::IS_LOGICAL',
854  'argumentCount' => '1'
855  ),
856  'ISNA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
857  'functionCall' => 'PHPExcel_Calculation_Functions::IS_NA',
858  'argumentCount' => '1'
859  ),
860  'ISNONTEXT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
861  'functionCall' => 'PHPExcel_Calculation_Functions::IS_NONTEXT',
862  'argumentCount' => '1'
863  ),
864  'ISNUMBER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
865  'functionCall' => 'PHPExcel_Calculation_Functions::IS_NUMBER',
866  'argumentCount' => '1'
867  ),
868  'ISODD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
869  'functionCall' => 'PHPExcel_Calculation_Functions::IS_ODD',
870  'argumentCount' => '1'
871  ),
872  'ISPMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
873  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
874  'argumentCount' => '4'
875  ),
876  'ISREF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
877  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
878  'argumentCount' => '1'
879  ),
880  'ISTEXT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
881  'functionCall' => 'PHPExcel_Calculation_Functions::IS_TEXT',
882  'argumentCount' => '1'
883  ),
884  'JIS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
885  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
886  'argumentCount' => '1'
887  ),
888  'KURT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
889  'functionCall' => 'PHPExcel_Calculation_Functions::KURT',
890  'argumentCount' => '1+'
891  ),
892  'LARGE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
893  'functionCall' => 'PHPExcel_Calculation_Functions::LARGE',
894  'argumentCount' => '2'
895  ),
896  'LCM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
897  'functionCall' => 'PHPExcel_Calculation_Functions::LCM',
898  'argumentCount' => '1+'
899  ),
900  'LEFT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
901  'functionCall' => 'PHPExcel_Calculation_Functions::LEFT',
902  'argumentCount' => '1,2'
903  ),
904  'LEFTB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
905  'functionCall' => 'PHPExcel_Calculation_Functions::LEFT',
906  'argumentCount' => '1,2'
907  ),
908  'LEN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
909  'functionCall' => 'PHPExcel_Calculation_Functions::STRINGLENGTH',
910  'argumentCount' => '1'
911  ),
912  'LENB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
913  'functionCall' => 'PHPExcel_Calculation_Functions::STRINGLENGTH',
914  'argumentCount' => '1'
915  ),
916  'LINEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
917  'functionCall' => 'PHPExcel_Calculation_Functions::LINEST',
918  'argumentCount' => '1-4'
919  ),
920  'LN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
921  'functionCall' => 'log',
922  'argumentCount' => '1'
923  ),
924  'LOG' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
925  'functionCall' => 'PHPExcel_Calculation_Functions::LOG_BASE',
926  'argumentCount' => '1,2'
927  ),
928  'LOG10' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
929  'functionCall' => 'log10',
930  'argumentCount' => '1'
931  ),
932  'LOGEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
933  'functionCall' => 'PHPExcel_Calculation_Functions::LOGEST',
934  'argumentCount' => '1-4'
935  ),
936  'LOGINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
937  'functionCall' => 'PHPExcel_Calculation_Functions::LOGINV',
938  'argumentCount' => '3'
939  ),
940  'LOGNORMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
941  'functionCall' => 'PHPExcel_Calculation_Functions::LOGNORMDIST',
942  'argumentCount' => '3'
943  ),
944  'LOOKUP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
945  'functionCall' => 'PHPExcel_Calculation_Functions::LOOKUP',
946  'argumentCount' => '2,3'
947  ),
948  'LOWER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
949  'functionCall' => 'PHPExcel_Calculation_Functions::LOWERCASE',
950  'argumentCount' => '1'
951  ),
953  'functionCall' => 'PHPExcel_Calculation_Functions::MATCH',
954  'argumentCount' => '2,3'
955  ),
956  'MAX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
957  'functionCall' => 'PHPExcel_Calculation_Functions::MAX',
958  'argumentCount' => '1+'
959  ),
960  'MAXA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
961  'functionCall' => 'PHPExcel_Calculation_Functions::MAXA',
962  'argumentCount' => '1+'
963  ),
964  'MDETERM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
965  'functionCall' => 'PHPExcel_Calculation_Functions::MDETERM',
966  'argumentCount' => '1'
967  ),
968  'MDURATION' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
969  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
970  'argumentCount' => '5,6'
971  ),
972  'MEDIAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
973  'functionCall' => 'PHPExcel_Calculation_Functions::MEDIAN',
974  'argumentCount' => '1+'
975  ),
976  'MID' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
977  'functionCall' => 'PHPExcel_Calculation_Functions::MID',
978  'argumentCount' => '3'
979  ),
980  'MIDB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
981  'functionCall' => 'PHPExcel_Calculation_Functions::MID',
982  'argumentCount' => '3'
983  ),
984  'MIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
985  'functionCall' => 'PHPExcel_Calculation_Functions::MIN',
986  'argumentCount' => '1+'
987  ),
988  'MINA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
989  'functionCall' => 'PHPExcel_Calculation_Functions::MINA',
990  'argumentCount' => '1+'
991  ),
992  'MINUTE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
993  'functionCall' => 'PHPExcel_Calculation_Functions::MINUTEOFHOUR',
994  'argumentCount' => '1'
995  ),
996  'MINVERSE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
997  'functionCall' => 'PHPExcel_Calculation_Functions::MINVERSE',
998  'argumentCount' => '1'
999  ),
1000  'MIRR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1001  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1002  'argumentCount' => '3'
1003  ),
1004  'MMULT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1005  'functionCall' => 'PHPExcel_Calculation_Functions::MMULT',
1006  'argumentCount' => '2'
1007  ),
1008  'MOD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1009  'functionCall' => 'PHPExcel_Calculation_Functions::MOD',
1010  'argumentCount' => '2'
1011  ),
1012  'MODE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1013  'functionCall' => 'PHPExcel_Calculation_Functions::MODE',
1014  'argumentCount' => '1+'
1015  ),
1016  'MONTH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1017  'functionCall' => 'PHPExcel_Calculation_Functions::MONTHOFYEAR',
1018  'argumentCount' => '1'
1019  ),
1020  'MROUND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1021  'functionCall' => 'PHPExcel_Calculation_Functions::MROUND',
1022  'argumentCount' => '2'
1023  ),
1024  'MULTINOMIAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1025  'functionCall' => 'PHPExcel_Calculation_Functions::MULTINOMIAL',
1026  'argumentCount' => '1+'
1027  ),
1028  'N' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
1029  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1030  'argumentCount' => '1'
1031  ),
1032  'NA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
1033  'functionCall' => 'PHPExcel_Calculation_Functions::NA',
1034  'argumentCount' => '0'
1035  ),
1036  'NEGBINOMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1037  'functionCall' => 'PHPExcel_Calculation_Functions::NEGBINOMDIST',
1038  'argumentCount' => '3'
1039  ),
1040  'NETWORKDAYS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1041  'functionCall' => 'PHPExcel_Calculation_Functions::NETWORKDAYS',
1042  'argumentCount' => '2+'
1043  ),
1044  'NOMINAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1045  'functionCall' => 'PHPExcel_Calculation_Functions::NOMINAL',
1046  'argumentCount' => '2'
1047  ),
1048  'NORMDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1049  'functionCall' => 'PHPExcel_Calculation_Functions::NORMDIST',
1050  'argumentCount' => '4'
1051  ),
1052  'NORMINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1053  'functionCall' => 'PHPExcel_Calculation_Functions::NORMINV',
1054  'argumentCount' => '3'
1055  ),
1056  'NORMSDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1057  'functionCall' => 'PHPExcel_Calculation_Functions::NORMSDIST',
1058  'argumentCount' => '1'
1059  ),
1060  'NORMSINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1061  'functionCall' => 'PHPExcel_Calculation_Functions::NORMSINV',
1062  'argumentCount' => '1'
1063  ),
1064  'NOT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
1065  'functionCall' => 'PHPExcel_Calculation_Functions::LOGICAL_NOT',
1066  'argumentCount' => '1'
1067  ),
1068  'NOW' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1069  'functionCall' => 'PHPExcel_Calculation_Functions::DATETIMENOW',
1070  'argumentCount' => '0'
1071  ),
1072  'NPER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1073  'functionCall' => 'PHPExcel_Calculation_Functions::NPER',
1074  'argumentCount' => '3-5'
1075  ),
1076  'NPV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1077  'functionCall' => 'PHPExcel_Calculation_Functions::NPV',
1078  'argumentCount' => '2+'
1079  ),
1080  'OCT2BIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
1081  'functionCall' => 'PHPExcel_Calculation_Functions::OCTTOBIN',
1082  'argumentCount' => '1,2'
1083  ),
1084  'OCT2DEC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
1085  'functionCall' => 'PHPExcel_Calculation_Functions::OCTTODEC',
1086  'argumentCount' => '1'
1087  ),
1088  'OCT2HEX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
1089  'functionCall' => 'PHPExcel_Calculation_Functions::OCTTOHEX',
1090  'argumentCount' => '1,2'
1091  ),
1092  'ODD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1093  'functionCall' => 'PHPExcel_Calculation_Functions::ODD',
1094  'argumentCount' => '1'
1095  ),
1096  'ODDFPRICE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1097  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1098  'argumentCount' => '8,9'
1099  ),
1100  'ODDFYIELD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1101  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1102  'argumentCount' => '8,9'
1103  ),
1104  'ODDLPRICE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1105  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1106  'argumentCount' => '7,8'
1107  ),
1108  'ODDLYIELD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1109  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1110  'argumentCount' => '7,8'
1111  ),
1112  'OFFSET' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
1113  'functionCall' => 'PHPExcel_Calculation_Functions::OFFSET',
1114  'argumentCount' => '3,5'
1115  ),
1116  'OR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
1117  'functionCall' => 'PHPExcel_Calculation_Functions::LOGICAL_OR',
1118  'argumentCount' => '1+'
1119  ),
1120  'PEARSON' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1121  'functionCall' => 'PHPExcel_Calculation_Functions::CORREL',
1122  'argumentCount' => '2'
1123  ),
1124  'PERCENTILE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1125  'functionCall' => 'PHPExcel_Calculation_Functions::PERCENTILE',
1126  'argumentCount' => '2'
1127  ),
1128  'PERCENTRANK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1129  'functionCall' => 'PHPExcel_Calculation_Functions::PERCENTRANK',
1130  'argumentCount' => '2,3'
1131  ),
1132  'PERMUT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1133  'functionCall' => 'PHPExcel_Calculation_Functions::PERMUT',
1134  'argumentCount' => '2'
1135  ),
1136  'PHONETIC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1137  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1138  'argumentCount' => '1'
1139  ),
1140  'PI' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1141  'functionCall' => 'pi',
1142  'argumentCount' => '0'
1143  ),
1144  'PMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1145  'functionCall' => 'PHPExcel_Calculation_Functions::PMT',
1146  'argumentCount' => '3-5'
1147  ),
1148  'POISSON' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1149  'functionCall' => 'PHPExcel_Calculation_Functions::POISSON',
1150  'argumentCount' => '3'
1151  ),
1152  'POWER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1153  'functionCall' => 'PHPExcel_Calculation_Functions::POWER',
1154  'argumentCount' => '2'
1155  ),
1156  'PPMT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1157  'functionCall' => 'PHPExcel_Calculation_Functions::PPMT',
1158  'argumentCount' => '4-6'
1159  ),
1160  'PRICE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1161  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1162  'argumentCount' => '6,7'
1163  ),
1164  'PRICEDISC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1165  'functionCall' => 'PHPExcel_Calculation_Functions::PRICEDISC',
1166  'argumentCount' => '4,5'
1167  ),
1168  'PRICEMAT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1169  'functionCall' => 'PHPExcel_Calculation_Functions::PRICEMAT',
1170  'argumentCount' => '5,6'
1171  ),
1172  'PROB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1173  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1174  'argumentCount' => '3,4'
1175  ),
1176  'PRODUCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1177  'functionCall' => 'PHPExcel_Calculation_Functions::PRODUCT',
1178  'argumentCount' => '1+'
1179  ),
1180  'PROPER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1181  'functionCall' => 'PHPExcel_Calculation_Functions::PROPERCASE',
1182  'argumentCount' => '1'
1183  ),
1184  'PV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1185  'functionCall' => 'PHPExcel_Calculation_Functions::PV',
1186  'argumentCount' => '3-5'
1187  ),
1188  'QUARTILE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1189  'functionCall' => 'PHPExcel_Calculation_Functions::QUARTILE',
1190  'argumentCount' => '2'
1191  ),
1192  'QUOTIENT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1193  'functionCall' => 'PHPExcel_Calculation_Functions::QUOTIENT',
1194  'argumentCount' => '2'
1195  ),
1196  'RADIANS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1197  'functionCall' => 'deg2rad',
1198  'argumentCount' => '1'
1199  ),
1200  'RAND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1201  'functionCall' => 'PHPExcel_Calculation_Functions::RAND',
1202  'argumentCount' => '0'
1203  ),
1204  'RANDBETWEEN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1205  'functionCall' => 'PHPExcel_Calculation_Functions::RAND',
1206  'argumentCount' => '2'
1207  ),
1208  'RANK' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1209  'functionCall' => 'PHPExcel_Calculation_Functions::RANK',
1210  'argumentCount' => '2,3'
1211  ),
1212  'RATE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1213  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1214  'argumentCount' => '3-6'
1215  ),
1216  'RECEIVED' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1217  'functionCall' => 'PHPExcel_Calculation_Functions::RECEIVED',
1218  'argumentCount' => '4-5'
1219  ),
1220  'REPLACE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1221  'functionCall' => 'PHPExcel_Calculation_Functions::REPLACE',
1222  'argumentCount' => '4'
1223  ),
1224  'REPLACEB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1225  'functionCall' => 'PHPExcel_Calculation_Functions::REPLACE',
1226  'argumentCount' => '4'
1227  ),
1228  'REPT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1229  'functionCall' => 'str_repeat',
1230  'argumentCount' => '2'
1231  ),
1232  'RIGHT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1233  'functionCall' => 'PHPExcel_Calculation_Functions::RIGHT',
1234  'argumentCount' => '1,2'
1235  ),
1236  'RIGHTB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1237  'functionCall' => 'PHPExcel_Calculation_Functions::RIGHT',
1238  'argumentCount' => '1,2'
1239  ),
1240  'ROMAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1241  'functionCall' => 'PHPExcel_Calculation_Functions::ROMAN',
1242  'argumentCount' => '1,2'
1243  ),
1244  'ROUND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1245  'functionCall' => 'round',
1246  'argumentCount' => '2'
1247  ),
1248  'ROUNDDOWN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1249  'functionCall' => 'PHPExcel_Calculation_Functions::ROUNDDOWN',
1250  'argumentCount' => '2'
1251  ),
1252  'ROUNDUP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1253  'functionCall' => 'PHPExcel_Calculation_Functions::ROUNDUP',
1254  'argumentCount' => '2'
1255  ),
1257  'functionCall' => 'PHPExcel_Calculation_Functions::ROW',
1258  'argumentCount' => '-1'
1259  ),
1261  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1262  'argumentCount' => '1'
1263  ),
1264  'RSQ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1265  'functionCall' => 'PHPExcel_Calculation_Functions::RSQ',
1266  'argumentCount' => '2'
1267  ),
1269  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1270  'argumentCount' => '1+'
1271  ),
1272  'SEARCH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1273  'functionCall' => 'PHPExcel_Calculation_Functions::SEARCHINSENSITIVE',
1274  'argumentCount' => '2,3'
1275  ),
1276  'SEARCHB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1277  'functionCall' => 'PHPExcel_Calculation_Functions::SEARCHINSENSITIVE',
1278  'argumentCount' => '2,3'
1279  ),
1280  'SECOND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1281  'functionCall' => 'PHPExcel_Calculation_Functions::SECONDOFMINUTE',
1282  'argumentCount' => '1'
1283  ),
1284  'SERIESSUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1285  'functionCall' => 'PHPExcel_Calculation_Functions::SERIESSUM',
1286  'argumentCount' => '4'
1287  ),
1288  'SIGN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1289  'functionCall' => 'PHPExcel_Calculation_Functions::SIGN',
1290  'argumentCount' => '1'
1291  ),
1292  'SIN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1293  'functionCall' => 'sin',
1294  'argumentCount' => '1'
1295  ),
1296  'SINH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1297  'functionCall' => 'sinh',
1298  'argumentCount' => '1'
1299  ),
1300  'SKEW' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1301  'functionCall' => 'PHPExcel_Calculation_Functions::SKEW',
1302  'argumentCount' => '1+'
1303  ),
1304  'SLN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1305  'functionCall' => 'PHPExcel_Calculation_Functions::SLN',
1306  'argumentCount' => '3'
1307  ),
1308  'SLOPE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1309  'functionCall' => 'PHPExcel_Calculation_Functions::SLOPE',
1310  'argumentCount' => '2'
1311  ),
1312  'SMALL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1313  'functionCall' => 'PHPExcel_Calculation_Functions::SMALL',
1314  'argumentCount' => '2'
1315  ),
1316  'SQRT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1317  'functionCall' => 'sqrt',
1318  'argumentCount' => '1'
1319  ),
1320  'SQRTPI' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1321  'functionCall' => 'PHPExcel_Calculation_Functions::SQRTPI',
1322  'argumentCount' => '1'
1323  ),
1324  'STANDARDIZE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1325  'functionCall' => 'PHPExcel_Calculation_Functions::STANDARDIZE',
1326  'argumentCount' => '3'
1327  ),
1328  'STDEV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1329  'functionCall' => 'PHPExcel_Calculation_Functions::STDEV',
1330  'argumentCount' => '1+'
1331  ),
1332  'STDEVA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1333  'functionCall' => 'PHPExcel_Calculation_Functions::STDEVA',
1334  'argumentCount' => '1+'
1335  ),
1336  'STDEVP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1337  'functionCall' => 'PHPExcel_Calculation_Functions::STDEVP',
1338  'argumentCount' => '1+'
1339  ),
1340  'STDEVPA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1341  'functionCall' => 'PHPExcel_Calculation_Functions::STDEVPA',
1342  'argumentCount' => '1+'
1343  ),
1344  'STEYX' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1345  'functionCall' => 'PHPExcel_Calculation_Functions::STEYX',
1346  'argumentCount' => '2'
1347  ),
1348  'SUBSTITUTE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1349  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1350  'argumentCount' => '3,4'
1351  ),
1352  'SUBTOTAL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1353  'functionCall' => 'PHPExcel_Calculation_Functions::SUBTOTAL',
1354  'argumentCount' => '2+'
1355  ),
1356  'SUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1357  'functionCall' => 'PHPExcel_Calculation_Functions::SUM',
1358  'argumentCount' => '1+'
1359  ),
1360  'SUMIF' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1361  'functionCall' => 'PHPExcel_Calculation_Functions::SUMIF',
1362  'argumentCount' => '2,3'
1363  ),
1364  'SUMIFS' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1365  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1366  'argumentCount' => '?'
1367  ),
1368  'SUMPRODUCT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1369  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1370  'argumentCount' => '1+'
1371  ),
1372  'SUMSQ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1373  'functionCall' => 'PHPExcel_Calculation_Functions::SUMSQ',
1374  'argumentCount' => '1+'
1375  ),
1376  'SUMX2MY2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1377  'functionCall' => 'PHPExcel_Calculation_Functions::SUMX2MY2',
1378  'argumentCount' => '2'
1379  ),
1380  'SUMX2PY2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1381  'functionCall' => 'PHPExcel_Calculation_Functions::SUMX2PY2',
1382  'argumentCount' => '2'
1383  ),
1384  'SUMXMY2' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1385  'functionCall' => 'PHPExcel_Calculation_Functions::SUMXMY2',
1386  'argumentCount' => '2'
1387  ),
1388  'SYD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1389  'functionCall' => 'PHPExcel_Calculation_Functions::SYD',
1390  'argumentCount' => '4'
1391  ),
1392  'T' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1393  'functionCall' => 'PHPExcel_Calculation_Functions::RETURNSTRING',
1394  'argumentCount' => '1'
1395  ),
1396  'TAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1397  'functionCall' => 'tan',
1398  'argumentCount' => '1'
1399  ),
1400  'TANH' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1401  'functionCall' => 'tanh',
1402  'argumentCount' => '1'
1403  ),
1404  'TBILLEQ' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1405  'functionCall' => 'PHPExcel_Calculation_Functions::TBILLEQ',
1406  'argumentCount' => '3'
1407  ),
1408  'TBILLPRICE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1409  'functionCall' => 'PHPExcel_Calculation_Functions::TBILLPRICE',
1410  'argumentCount' => '3'
1411  ),
1412  'TBILLYIELD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1413  'functionCall' => 'PHPExcel_Calculation_Functions::TBILLYIELD',
1414  'argumentCount' => '3'
1415  ),
1416  'TDIST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1417  'functionCall' => 'PHPExcel_Calculation_Functions::TDIST',
1418  'argumentCount' => '3'
1419  ),
1420  'TEXT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1421  'functionCall' => 'PHPExcel_Calculation_Functions::TEXTFORMAT',
1422  'argumentCount' => '2'
1423  ),
1424  'TIME' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1425  'functionCall' => 'PHPExcel_Calculation_Functions::TIME',
1426  'argumentCount' => '3'
1427  ),
1428  'TIMEVALUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1429  'functionCall' => 'PHPExcel_Calculation_Functions::TIMEVALUE',
1430  'argumentCount' => '1'
1431  ),
1432  'TINV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1433  'functionCall' => 'PHPExcel_Calculation_Functions::TINV',
1434  'argumentCount' => '2'
1435  ),
1436  'TODAY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1437  'functionCall' => 'PHPExcel_Calculation_Functions::DATENOW',
1438  'argumentCount' => '0'
1439  ),
1440  'TRANSPOSE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
1441  'functionCall' => 'PHPExcel_Calculation_Functions::TRANSPOSE',
1442  'argumentCount' => '1'
1443  ),
1444  'TREND' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1445  'functionCall' => 'PHPExcel_Calculation_Functions::TREND',
1446  'argumentCount' => '1-4'
1447  ),
1448  'TRIM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1449  'functionCall' => 'PHPExcel_Calculation_Functions::TRIMSPACES',
1450  'argumentCount' => '1'
1451  ),
1452  'TRIMMEAN' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1453  'functionCall' => 'PHPExcel_Calculation_Functions::TRIMMEAN',
1454  'argumentCount' => '2'
1455  ),
1456  'TRUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
1457  'functionCall' => 'PHPExcel_Calculation_Functions::LOGICAL_TRUE',
1458  'argumentCount' => '0'
1459  ),
1460  'TRUNC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
1461  'functionCall' => 'PHPExcel_Calculation_Functions::TRUNC',
1462  'argumentCount' => '1,2'
1463  ),
1464  'TTEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1465  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1466  'argumentCount' => '4'
1467  ),
1468  'TYPE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
1469  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1470  'argumentCount' => '1'
1471  ),
1472  'UPPER' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1473  'functionCall' => 'PHPExcel_Calculation_Functions::UPPERCASE',
1474  'argumentCount' => '1'
1475  ),
1476  'USDOLLAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1477  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1478  'argumentCount' => '2'
1479  ),
1480  'VALUE' => array('category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
1481  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1482  'argumentCount' => '1'
1483  ),
1484  'VAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1485  'functionCall' => 'PHPExcel_Calculation_Functions::VARFunc',
1486  'argumentCount' => '1+'
1487  ),
1488  'VARA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1489  'functionCall' => 'PHPExcel_Calculation_Functions::VARA',
1490  'argumentCount' => '1+'
1491  ),
1492  'VARP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1493  'functionCall' => 'PHPExcel_Calculation_Functions::VARP',
1494  'argumentCount' => '1+'
1495  ),
1496  'VARPA' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1497  'functionCall' => 'PHPExcel_Calculation_Functions::VARPA',
1498  'argumentCount' => '1+'
1499  ),
1500  'VDB' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1501  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1502  'argumentCount' => '5-7'
1503  ),
1504  'VERSION' => array('category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
1505  'functionCall' => 'PHPExcel_Calculation_Functions::VERSION',
1506  'argumentCount' => '0'
1507  ),
1508  'VLOOKUP' => array('category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
1509  'functionCall' => 'PHPExcel_Calculation_Functions::VLOOKUP',
1510  'argumentCount' => '3,4'
1511  ),
1512  'WEEKDAY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1513  'functionCall' => 'PHPExcel_Calculation_Functions::DAYOFWEEK',
1514  'argumentCount' => '1,2'
1515  ),
1516  'WEEKNUM' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1517  'functionCall' => 'PHPExcel_Calculation_Functions::WEEKOFYEAR',
1518  'argumentCount' => '1,2'
1519  ),
1520  'WEIBULL' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1521  'functionCall' => 'PHPExcel_Calculation_Functions::WEIBULL',
1522  'argumentCount' => '4'
1523  ),
1524  'WORKDAY' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1525  'functionCall' => 'PHPExcel_Calculation_Functions::WORKDAY',
1526  'argumentCount' => '2+'
1527  ),
1528  'XIRR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1529  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1530  'argumentCount' => '2,3'
1531  ),
1532  'XNPV' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1533  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1534  'argumentCount' => '3'
1535  ),
1536  'YEAR' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1537  'functionCall' => 'PHPExcel_Calculation_Functions::YEAR',
1538  'argumentCount' => '1'
1539  ),
1540  'YEARFRAC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
1541  'functionCall' => 'PHPExcel_Calculation_Functions::YEARFRAC',
1542  'argumentCount' => '2,3'
1543  ),
1544  'YIELD' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1545  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1546  'argumentCount' => '6,7'
1547  ),
1548  'YIELDDISC' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1549  'functionCall' => 'PHPExcel_Calculation_Functions::YIELDDISC',
1550  'argumentCount' => '4,5'
1551  ),
1552  'YIELDMAT' => array('category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
1553  'functionCall' => 'PHPExcel_Calculation_Functions::YIELDMAT',
1554  'argumentCount' => '5,6'
1555  ),
1556  'ZTEST' => array('category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
1557  'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
1558  'argumentCount' => '?'
1559  )
1560  );
1561 
1562 
1563  // Internal functions used for special control purposes
1564  private $_controlFunctions = array(
1565  'MKMATRIX' => array('argumentCount' => '*',
1566  'functionCall' => array('self','_mkMatrix')
1567  )
1568  );
1569 
1570 
1571 
1572 
1579  public static function getInstance() {
1580  if (!isset(self::$_instance) || is_null(self::$_instance)) {
1581  self::$_instance = new PHPExcel_Calculation();
1582  }
1583 
1584  return self::$_instance;
1585  } // function getInstance()
1586 
1587 
1594  public final function __clone() {
1595  throw new Exception ( 'Cloning a Singleton is not allowed!' );
1596  } // function __clone()
1597 
1598 
1606  public static function setArrayReturnType($returnType) {
1607  if (($returnType == self::RETURN_ARRAY_AS_VALUE) ||
1608  ($returnType == self::RETURN_ARRAY_AS_ARRAY)) {
1609  self::$returnArrayAsType = $returnType;
1610  return True;
1611  }
1612  return False;
1613  } // function setExcelCalendar()
1614 
1615 
1622  public static function getArrayReturnType() {
1623  return self::$returnArrayAsType;
1624  } // function getExcelCalendar()
1625 
1626 
1633  public function getCalculationCacheEnabled() {
1635  } // function getCalculationCacheEnabled()
1636 
1637 
1644  public function setCalculationCacheEnabled($pValue = true) {
1645  $this->_calculationCacheEnabled = $pValue;
1646  $this->clearCalculationCache();
1647  } // function setCalculationCacheEnabled()
1648 
1649 
1653  public function enableCalculationCache() {
1654  $this->setCalculationCacheEnabled(true);
1655  } // function enableCalculationCache()
1656 
1657 
1661  public function disableCalculationCache() {
1662  $this->setCalculationCacheEnabled(false);
1663  } // function disableCalculationCache()
1664 
1665 
1669  public function clearCalculationCache() {
1670  $this->_calculationCache = array();
1671  } // function clearCalculationCache()
1672 
1673 
1681  } // getCalculationCacheExpirationTime()
1682 
1683 
1689  public function setCalculationCacheExpirationTime($pValue = 0.01) {
1690  $this->_calculationCacheExpirationTime = $pValue;
1691  } // function setCalculationCacheExpirationTime()
1692 
1693 
1694 
1695 
1702  public static function _wrapResult($value) {
1703  if (is_string($value)) {
1704  // Error values cannot be "wrapped"
1705  if (preg_match('/^'.self::CALCULATION_REGEXP_ERROR.'$/i', $value, $match)) {
1706  // Return Excel errors "as is"
1707  return $value;
1708  }
1709  // Return strings wrapped in quotes
1710  return '"'.$value.'"';
1711  // Convert numeric errors to NaN error
1712  } else if((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) {
1714  }
1715 
1716  return $value;
1717  } // function _wrapResult()
1718 
1719 
1726  public static function _unwrapResult($value) {
1727  if (is_string($value)) {
1728  if ((strlen($value) > 0) && ($value{0} == '"') && (substr($value,-1) == '"')) {
1729  return substr($value,1,-1);
1730  }
1731  // Convert numeric errors to NaN error
1732  } else if((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) {
1734  }
1735  return $value;
1736  } // function _unwrapResult()
1737 
1738 
1739 
1740 
1750  public function calculate(PHPExcel_Cell $pCell = null) {
1751  return $this->calculateCellValue($pCell);
1752  } // function calculate()
1753 
1754 
1764  public function calculateCellValue(PHPExcel_Cell $pCell = null, $resetLog = true) {
1765  if ($resetLog) {
1766  // Initialise the logging settings if requested
1767  $this->formulaError = null;
1768  $this->debugLog = array();
1769  $this->debugLogStack = array();
1770  }
1771 
1772  // Read the formula from the cell
1773  if (is_null($pCell)) {
1774  return null;
1775  }
1776  $formula = $pCell->getValue();
1777  $cellID = $pCell->getCoordinate();
1778 
1779  // Execute the calculation for the cell formula
1780  return self::_unwrapResult($this->_calculateFormulaValue($formula, $cellID, $pCell));
1781  } // function calculateCellValue(
1782 
1783 
1791  public function parseFormula($formula) {
1792  // Basic validation that this is indeed a formula
1793  // We return an empty array if not
1794  $formula = trim($formula);
1795  if ($formula{0} != '=') return array();
1796  $formula = trim(substr($formula,1));
1797  $formulaLength = strlen($formula);
1798  if ($formulaLength < 1) return array();
1799 
1800  // Parse the formula and return the token stack
1801  return $this->_parseFormula($formula);
1802  } // function parseFormula()
1803 
1804 
1812  public function calculateFormula($formula, $cellID=null, PHPExcel_Cell $pCell = null) {
1813  // Initialise the logging settings
1814  $this->formulaError = null;
1815  $this->debugLog = array();
1816  $this->debugLogStack = array();
1817 
1818  // Disable calculation cacheing because it only applies to cell calculations, not straight formulae
1819  // But don't actually flush any cache
1820  $resetCache = $this->getCalculationCacheEnabled();
1821  $this->_calculationCacheEnabled = false;
1822  // Execute the calculation
1823  $result = self::_unwrapResult($this->_calculateFormulaValue($formula, $cellID, $pCell));
1824  // Reset calculation cacheing to its previous state
1825  $this->_calculationCacheEnabled = $resetCache;
1826 
1827  return $result;
1828  } // function calculateFormula()
1829 
1830 
1840  public function _calculateFormulaValue($formula, $cellID=null, PHPExcel_Cell $pCell = null) {
1841 // echo '<b>'.$cellID.'</b><br />';
1842  $cellValue = '';
1843 
1844  // Basic validation that this is indeed a formula
1845  // We simply return the "cell value" (formula) if not
1846  $formula = trim($formula);
1847  if ($formula{0} != '=') return self::_wrapResult($formula);
1848  $formula = trim(substr($formula,1));
1849  $formulaLength = strlen($formula);
1850  if ($formulaLength < 1) return self::_wrapResult($formula);
1851 
1852  // Is calculation cacheing enabled?
1853  if (!is_null($cellID)) {
1854  if ($this->_calculationCacheEnabled) {
1855  // Is the value present in calculation cache?
1856 // echo 'Testing cache value<br />';
1857  if (isset($this->_calculationCache[$pCell->getParent()->getTitle()][$pCell->getCoordinate()])) {
1858 // echo 'Value is in cache<br />';
1859  $this->_writeDebug($cellID,'Testing cache value');
1860  // Is cache still valid?
1861  if ((time() + microtime()) - $this->_calculationCache[$pCell->getParent()->getTitle()][$pCell->getCoordinate()]['time'] < $this->_calculationCacheExpirationTime) {
1862 // echo 'Cache time is still valid<br />';
1863  $this->_writeDebug($cellID,'Retrieving value from cache');
1864  // Return the cached result
1865  $returnValue = $this->_calculationCache[$pCell->getParent()->getTitle()][$pCell->getCoordinate()]['data'];
1866 // echo 'Retrieving data value of '.$returnValue.' for '.$pCell->getCoordinate().' from cache<br />';
1867  if (is_array($returnValue)) {
1868  return array_shift(PHPExcel_Calculation_Functions::flattenArray($returnValue));
1869  }
1870  return $returnValue;
1871  } else {
1872 // echo 'Cache has expired<br />';
1873  $this->_writeDebug($cellID,'Cache value has expired');
1874  // Clear the cache if it's no longer valid
1875  unset($this->_calculationCache[$pCell->getParent()->getTitle()][$pCell->getCoordinate()]);
1876  }
1877  }
1878  }
1879  }
1880 
1881  $this->debugLogStack[] = $cellID;
1882  // Parse the formula onto the token stack and calculate the value
1883  $cellValue = $this->_processTokenStack($this->_parseFormula($formula), $cellID, $pCell);
1884  array_pop($this->debugLogStack);
1885 
1886  // Save to calculation cache
1887  if (!is_null($cellID)) {
1888  if ($this->_calculationCacheEnabled) {
1889  $this->_calculationCache[$pCell->getParent()->getTitle()][$pCell->getCoordinate()]['time'] = (time() + microtime());
1890  $this->_calculationCache[$pCell->getParent()->getTitle()][$pCell->getCoordinate()]['data'] = $cellValue;
1891  }
1892  }
1893 
1894  // Return the calculated value
1895  if (is_array($cellValue)) {
1896  $cellValue = array_shift(PHPExcel_Calculation_Functions::flattenArray($cellValue));
1897  }
1898 
1899  return $cellValue;
1900  } // function _calculateFormulaValue()
1901 
1902 
1909  private static function _checkMatrixOperands(&$operand1,&$operand2,$resize = 1) {
1910  // Examine each of the two operands, and turn them into an array if they aren't one already
1911  // Note that this function should only be called if one or both of the operand is already an array
1912  if (!is_array($operand1)) {
1913  list($matrixRows,$matrixColumns) = self::_getMatrixDimensions($operand2);
1914  $operand1 = array_fill(0,$matrixRows,array_fill(0,$matrixColumns,$operand1));
1915  $resize = 0;
1916  } elseif (!is_array($operand2)) {
1917  list($matrixRows,$matrixColumns) = self::_getMatrixDimensions($operand1);
1918  $operand2 = array_fill(0,$matrixRows,array_fill(0,$matrixColumns,$operand2));
1919  $resize = 0;
1920  }
1921 
1922  // Given two matrices of (potentially) unequal size, convert the smaller in each dimension to match the larger
1923  if ($resize == 2) {
1924  self::_resizeMatricesExtend($operand1,$operand2);
1925  } elseif ($resize == 1) {
1926  self::_resizeMatricesShrink($operand1,$operand2);
1927  }
1928  } // function _checkMatrixOperands()
1929 
1930 
1937  private static function _reindexMatrixDimensions($matrix) {
1938  foreach($matrix as $rowKey => $rowValue) {
1939  $matrix[$rowKey] = array_values($rowValue);
1940  }
1941  return array_values($matrix);
1942  } // function _getMatrixDimensions()
1943 
1944 
1951  private static function _getMatrixDimensions(&$matrix) {
1952  $matrixRows = count($matrix);
1953  $matrixColumns = 0;
1954  foreach($matrix as $rowKey => $rowValue) {
1955  $colCount = count($rowValue);
1956  if ($colCount > $matrixColumns) {
1957  $matrixColumns = $colCount;
1958  }
1959  $matrix[$rowKey] = array_values($rowValue);
1960  }
1961  $matrix = array_values($matrix);
1962  return array($matrixRows,$matrixColumns);
1963  } // function _getMatrixDimensions()
1964 
1965 
1972  private static function _resizeMatricesShrink(&$matrix1,&$matrix2) {
1973  list($matrix1Rows,$matrix1Columns) = self::_getMatrixDimensions($matrix1);
1974  list($matrix2Rows,$matrix2Columns) = self::_getMatrixDimensions($matrix2);
1975 
1976  if (($matrix2Columns < $matrix1Columns) || ($matrix2Rows < $matrix1Rows)) {
1977  if ($matrix2Columns < $matrix1Columns) {
1978  for ($i = 0; $i < $matrix1Rows; ++$i) {
1979  for ($j = $matrix2Columns; $j < $matrix1Columns; ++$j) {
1980  unset($matrix1[$i][$j]);
1981  }
1982  }
1983  }
1984  if ($matrix2Rows < $matrix1Rows) {
1985  for ($i = $matrix2Rows; $i < $matrix1Rows; ++$i) {
1986  unset($matrix1[$i]);
1987  }
1988  }
1989  }
1990 
1991  if (($matrix1Columns < $matrix2Columns) || ($matrix1Rows < $matrix2Rows)) {
1992  if ($matrix1Columns < $matrix2Columns) {
1993  for ($i = 0; $i < $matrix2Rows; ++$i) {
1994  for ($j = $matrix1Columns; $j < $matrix2Columns; ++$j) {
1995  unset($matrix2[$i][$j]);
1996  }
1997  }
1998  }
1999  if ($matrix1Rows < $matrix2Rows) {
2000  for ($i = $matrix1Rows; $i < $matrix2Rows; ++$i) {
2001  unset($matrix2[$i]);
2002  }
2003  }
2004  }
2005  } // function _resizeMatricesShrink()
2006 
2007 
2014  private static function _resizeMatricesExtend(&$matrix1,&$matrix2) {
2015  list($matrix1Rows,$matrix1Columns) = self::_getMatrixDimensions($matrix1);
2016  list($matrix2Rows,$matrix2Columns) = self::_getMatrixDimensions($matrix2);
2017 
2018  if (($matrix2Columns < $matrix1Columns) || ($matrix2Rows < $matrix1Rows)) {
2019  if ($matrix2Columns < $matrix1Columns) {
2020  for ($i = 0; $i < $matrix2Rows; ++$i) {
2021  $x = $matrix2[$i][$matrix2Columns-1];
2022  for ($j = $matrix2Columns; $j < $matrix1Columns; ++$j) {
2023  $matrix2[$i][$j] = $x;
2024  }
2025  }
2026  }
2027  if ($matrix2Rows < $matrix1Rows) {
2028  $x = $matrix2[$matrix2Rows-1];
2029  for ($i = 0; $i < $matrix1Rows; ++$i) {
2030  $matrix2[$i] = $x;
2031  }
2032  }
2033  }
2034 
2035  if (($matrix1Columns < $matrix2Columns) || ($matrix1Rows < $matrix2Rows)) {
2036  if ($matrix1Columns < $matrix2Columns) {
2037  for ($i = 0; $i < $matrix1Rows; ++$i) {
2038  $x = $matrix1[$i][$matrix1Columns-1];
2039  for ($j = $matrix1Columns; $j < $matrix2Columns; ++$j) {
2040  $matrix1[$i][$j] = $x;
2041  }
2042  }
2043  }
2044  if ($matrix1Rows < $matrix2Rows) {
2045  $x = $matrix1[$matrix1Rows-1];
2046  for ($i = 0; $i < $matrix2Rows; ++$i) {
2047  $matrix1[$i] = $x;
2048  }
2049  }
2050  }
2051  } // function _resizeMatricesExtend()
2052 
2053 
2060  private static function _showValue($value) {
2061  if (is_array($value)) {
2062  $retVal = '';
2063  $i = 0;
2064  foreach($value as $row) {
2065  if (is_array($row)) {
2066  if ($i > 0) { $retVal .= '; '; }
2067  $j = 0;
2068  foreach($row as $column) {
2069  if ($j > 0) { $retVal .= ', '; }
2070  $retVal .= $column;
2071  ++$j;
2072  }
2073  } else {
2074  if ($i > 0) { $retVal .= ', '; }
2075  $retVal .= $row;
2076  }
2077  ++$i;
2078  }
2079  return '{ '.$retVal.' }';
2080  } elseif(is_bool($value)) {
2081  return ($value) ? 'TRUE' : 'FALSE';
2082  }
2083 
2084  return $value;
2085  } // function _showValue()
2086 
2087 
2094  private static function _showTypeDetails($value) {
2095  switch (gettype($value)) {
2096  case 'double' :
2097  case 'float' :
2098  $typeString = 'a floating point number';
2099  break;
2100  case 'integer' :
2101  $typeString = 'an integer number';
2102  break;
2103  case 'boolean' :
2104  $typeString = 'a boolean';
2105  break;
2106  case 'array' :
2107  $typeString = 'a matrix';
2108  break;
2109  case 'string' :
2110  if ($value == '') {
2111  return 'an empty string';
2112  } elseif ($value{0} == '#') {
2113  return 'a '.$value.' error';
2114  } else {
2115  $typeString = 'a string';
2116  }
2117  break;
2118  case 'NULL' :
2119  return 'a null value';
2120  }
2121  return $typeString.' with a value of '.self::_showValue($value);
2122  } // function _showTypeDetails()
2123 
2124 
2125  private static function _convertMatrixReferences($formula) {
2126  static $matrixReplaceFrom = array('{',';','}');
2127  static $matrixReplaceTo = array('MKMATRIX(MKMATRIX(','),MKMATRIX(','))');
2128 
2129  // Convert any Excel matrix references to the MKMATRIX() function
2130  if (strpos($formula,'{') !== false) {
2131  // Open and Closed counts used for trapping mismatched braces in the formula
2132  $openCount = $closeCount = 0;
2133  // If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators
2134  if (strpos($formula,'"') !== false) {
2135  // So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded
2136  // the formula
2137  $temp = explode('"',$formula);
2138  $i = 0;
2139  foreach($temp as &$value) {
2140  // Only count/replace in alternate array entries
2141  if (($i++ % 2) == 0) {
2142  $openCount += substr_count($value,'{');
2143  $closeCount += substr_count($value,'}');
2144  $value = str_replace($matrixReplaceFrom,$matrixReplaceTo,$value);
2145  }
2146  }
2147  unset($value);
2148  // Then rebuild the formula string
2149  $formula = implode('"',$temp);
2150  } else {
2151  // If there's no quoted strings, then we do a simple count/replace
2152  $openCount += substr_count($formula,'{');
2153  $closeCount += substr_count($formula,'}');
2154  $formula = str_replace($matrixReplaceFrom,$matrixReplaceTo,$formula);
2155  }
2156  // Trap for mismatched braces and trigger an appropriate error
2157  if ($openCount < $closeCount) {
2158  if ($openCount > 0) {
2159  return $this->_raiseFormulaError("Formula Error: Mismatched matrix braces '}'");
2160  } else {
2161  return $this->_raiseFormulaError("Formula Error: Unexpected '}' encountered");
2162  }
2163  } elseif ($openCount > $closeCount) {
2164  if ($closeCount > 0) {
2165  return $this->_raiseFormulaError("Formula Error: Mismatched matrix braces '{'");
2166  } else {
2167  return $this->_raiseFormulaError("Formula Error: Unexpected '{' encountered");
2168  }
2169  }
2170  }
2171 
2172  return $formula;
2173  } // function _convertMatrixReferences()
2174 
2175 
2176  private static function _mkMatrix() {
2177  return func_get_args();
2178  } // function _mkMatrix()
2179 
2180 
2181  // Convert infix to postfix notation
2182  private function _parseFormula($formula) {
2183  if (($formula = self::_convertMatrixReferences(trim($formula))) === false) {
2184  return false;
2185  }
2186 
2187  // Binary Operators
2188  // These operators always work on two values
2189  // Array key is the operator, the value indicates whether this is a left or right associative operator
2190  $operatorAssociativity = array('^' => 0, // Exponentiation
2191  '*' => 0, '/' => 0, // Multiplication and Division
2192  '+' => 0, '-' => 0, // Addition and Subtraction
2193  '&' => 1, // Concatenation
2194  '>' => 0, '<' => 0, '=' => 0, '>=' => 0, '<=' => 0, '<>' => 0 // Comparison
2195  );
2196  // Comparison (Boolean) Operators
2197  // These operators work on two values, but always return a boolean result
2198  $comparisonOperators = array('>', '<', '=', '>=', '<=', '<>');
2199 
2200  // Operator Precedence
2201  // This list includes all valid operators, whether binary (including boolean) or unary (such as %)
2202  // Array key is the operator, the value is its precedence
2203  $operatorPrecedence = array('_' => 6, // Negation
2204  '%' => 5, // Percentage
2205  '^' => 4, // Exponentiation
2206  '*' => 3, '/' => 3, // Multiplication and Division
2207  '+' => 2, '-' => 2, // Addition and Subtraction
2208  '&' => 1, // Concatenation
2209  '>' => 0, '<' => 0, '=' => 0, '>=' => 0, '<=' => 0, '<>' => 0 // Comparison
2210  );
2211 
2212  $regexpMatchString = '/^('.self::CALCULATION_REGEXP_FUNCTION.
2213  '|'.self::CALCULATION_REGEXP_NUMBER.
2214  '|'.self::CALCULATION_REGEXP_STRING.
2215  '|'.self::CALCULATION_REGEXP_OPENBRACE.
2216  '|'.self::CALCULATION_REGEXP_CELLREF.
2217  '|'.self::CALCULATION_REGEXP_NAMEDRANGE.
2218  ')/i';
2219 
2220  // Start with initialisation
2221  $index = 0;
2222  $stack = new PHPExcel_Token_Stack;
2223  $output = array();
2224  $expectingOperator = false; // We use this test in syntax-checking the expression to determine when a
2225  // - is a negation or + is a positive operator rather than an operation
2226  $expectingOperand = false; // We use this test in syntax-checking the expression to determine whether an operand
2227  // should be null in a function call
2228  // The guts of the lexical parser
2229  // Loop through the formula extracting each operator and operand in turn
2230  while(True) {
2231 // echo 'Assessing Expression <b>'.substr($formula, $index).'</b><br />';
2232  $opCharacter = $formula{$index}; // Get the first character of the value at the current index position
2233 // echo 'Initial character of expression block is '.$opCharacter.'<br />';
2234  if ((in_array($opCharacter, $comparisonOperators)) && (strlen($formula) > $index) && (in_array($formula{$index+1}, $comparisonOperators))) {
2235  $opCharacter .= $formula{++$index};
2236 // echo 'Initial character of expression block is comparison operator '.$opCharacter.'<br />';
2237  }
2238 
2239  // Find out if we're currently at the beginning of a number, variable, cell reference, function, parenthesis or operand
2240  $isOperandOrFunction = preg_match($regexpMatchString, substr($formula, $index), $match);
2241 // echo '$isOperandOrFunction is '.(($isOperandOrFunction)?'True':'False').'<br />';
2242 
2243  if ($opCharacter == '-' && !$expectingOperator) { // Is it a negation instead of a minus?
2244 // echo 'Element is a Negation operator<br />';
2245  $stack->push('_'); // Put a negation on the stack
2246  ++$index; // and drop the negation symbol
2247  } elseif ($opCharacter == '%' && $expectingOperator) {
2248 // echo 'Element is a Percentage operator<br />';
2249  $stack->push('%'); // Put a percentage on the stack
2250  ++$index;
2251  } elseif ($opCharacter == '+' && !$expectingOperator) { // Positive (rather than plus) can be discarded?
2252 // echo 'Element is a Positive number, not Plus operator<br />';
2253  ++$index; // Drop the redundant plus symbol
2254  } elseif (($opCharacter == '_') && (!$isOperandOrFunction)) { // We have to explicitly deny an underscore, because it's legal on
2255  return $this->_raiseFormulaError("Formula Error: Illegal character '_'"); // the stack but not in the input expression
2256  // Note that _ is a valid first character in named ranges
2257  // and this will need modifying soon when we start integrating
2258  // with PHPExcel proper
2259 
2260  } elseif ((in_array($opCharacter, $this->_operators) or $isOperandOrFunction) && $expectingOperator) { // Are we putting an operator on the stack?
2261 // echo 'Element with value '.$opCharacter.' is an Operator<br />';
2262  while($stack->count() > 0 &&
2263  ($o2 = $stack->last()) &&
2264  in_array($o2, $this->_operators) &&
2265  ($operatorAssociativity[$opCharacter] ? $operatorPrecedence[$opCharacter] < $operatorPrecedence[$o2] : $operatorPrecedence[$opCharacter] <= $operatorPrecedence[$o2])) {
2266  $output[] = $stack->pop(); // Swap operands and higher precedence operators from the stack to the output
2267  }
2268  $stack->push($opCharacter); // Finally put our current operator onto the stack
2269  ++$index;
2270  $expectingOperator = false;
2271 
2272  } elseif ($opCharacter == ')' && $expectingOperator) { // Are we expecting to close a parenthesis?
2273 // echo 'Element is a Closing bracket<br />';
2274  $expectingOperand = false;
2275  while (($o2 = $stack->pop()) != '(') { // Pop off the stack back to the last (
2276  if (is_null($o2)) return $this->_raiseFormulaError('Formula Error: Unexpected closing brace ")"');
2277  else $output[] = $o2;
2278  }
2279  if (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $stack->last(2), $matches)) { // Did this parenthesis just close a function?
2280  $functionName = $matches[1]; // Get the function name
2281 // echo 'Closed Function is '.$functionName.'<br />';
2282  $argumentCount = $stack->pop(); // See how many arguments there were (argument count is the next value stored on the stack)
2283 // if ($argumentCount == 0) {
2284 // echo 'With no arguments<br />';
2285 // } elseif ($argumentCount == 1) {
2286 // echo 'With 1 argument<br />';
2287 // } else {
2288 // echo 'With '.$argumentCount.' arguments<br />';
2289 // }
2290  $output[] = $argumentCount; // Dump the argument count on the output
2291  $output[] = $stack->pop(); // Pop the function and push onto the output
2292  if (array_key_exists($functionName, $this->_controlFunctions)) {
2293 // echo 'Built-in function '.$functionName.'<br />';
2294  $expectedArgumentCount = $this->_controlFunctions[$functionName]['argumentCount'];
2295  $functionCall = $this->_controlFunctions[$functionName]['functionCall'];
2296  } elseif (array_key_exists($functionName, $this->_PHPExcelFunctions)) {
2297 // echo 'PHPExcel function '.$functionName.'<br />';
2298  $expectedArgumentCount = $this->_PHPExcelFunctions[$functionName]['argumentCount'];
2299  $functionCall = $this->_PHPExcelFunctions[$functionName]['functionCall'];
2300  } else { // did we somehow push a non-function on the stack? this should never happen
2301  return $this->_raiseFormulaError("Formula Error: Internal error, non-function on stack");
2302  }
2303  // Check the argument count
2304  $argumentCountError = False;
2305  if (is_numeric($expectedArgumentCount)) {
2306  if ($expectedArgumentCount < 0) {
2307 // echo '$expectedArgumentCount is between 0 and '.abs($expectedArgumentCount).'<br />';
2308  if ($argumentCount > abs($expectedArgumentCount)) {
2309  $argumentCountError = True;
2310  $expectedArgumentCountString = 'no more than '.abs($expectedArgumentCount);
2311  }
2312  } else {
2313 // echo '$expectedArgumentCount is numeric '.$expectedArgumentCount.'<br />';
2314  if ($argumentCount != $expectedArgumentCount) {
2315  $argumentCountError = True;
2316  $expectedArgumentCountString = $expectedArgumentCount;
2317  }
2318  }
2319  } elseif ($expectedArgumentCount != '*') {
2320  $isOperandOrFunction = preg_match('/(\d*)([-+,])(\d*)/',$expectedArgumentCount,$argMatch);
2321 // print_r($argMatch);
2322 // echo '<br />';
2323  switch ($argMatch[2]) {
2324  case '+' :
2325  if ($argumentCount < $argMatch[1]) {
2326  $argumentCountError = True;
2327  $expectedArgumentCountString = $argMatch[1].' or more ';
2328  }
2329  break;
2330  case '-' :
2331  if (($argumentCount < $argMatch[1]) || ($argumentCount > $argMatch[3])) {
2332  $argumentCountError = True;
2333  $expectedArgumentCountString = 'between '.$argMatch[1].' and '.$argMatch[3];
2334  }
2335  break;
2336  case ',' :
2337  if (($argumentCount != $argMatch[1]) && ($argumentCount != $argMatch[3])) {
2338  $argumentCountError = True;
2339  $expectedArgumentCountString = 'either '.$argMatch[1].' or '.$argMatch[3];
2340  }
2341  break;
2342  }
2343  }
2344  if ($argumentCountError) {
2345  return $this->_raiseFormulaError("Formula Error: Wrong number of arguments for $functionName() function: $argumentCount given, ".$expectedArgumentCountString." expected");
2346  }
2347  }
2348  ++$index;
2349 
2350  } elseif ($opCharacter == ',') { // Is this the comma separator for function arguments?
2351 // echo 'Element is a Function argument separator<br />';
2352  while (($o2 = $stack->pop()) != '(') {
2353  if (is_null($o2)) return $this->_raiseFormulaError("Formula Error: Unexpected ','");
2354  else $output[] = $o2; // pop the argument expression stuff and push onto the output
2355  }
2356  // If we've a comma when we're expecting an operand, then what we actually have is a null operand;
2357  // so push a null onto the stack
2358  if (($expectingOperand) || (!$expectingOperator)) {
2359  $output[] = $this->_ExcelConstants['NULL'];
2360  }
2361  // make sure there was a function
2362  if (!preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $stack->last(2), $matches))
2363  return $this->_raiseFormulaError("Formula Error: Unexpected ','");
2364  $stack->push($stack->pop()+1); // increment the argument count
2365  $stack->push('('); // put the ( back on, we'll need to pop back to it again
2366  $expectingOperator = false;
2367  $expectingOperand = true;
2368  ++$index;
2369 
2370  } elseif ($opCharacter == '(' && !$expectingOperator) {
2371 // echo 'Element is an Opening Bracket<br />';
2372  $stack->push('(');
2373  ++$index;
2374 
2375  } elseif ($isOperandOrFunction && !$expectingOperator) { // do we now have a function/variable/number?
2376  $expectingOperator = true;
2377  $expectingOperand = false;
2378  $val = $match[1];
2379  $length = strlen($val);
2380 // echo 'Element with value '.$val.' is an Operand, Variable, Constant, String, Number, Cell Reference or Function<br />';
2381 
2382  if (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $val, $matches)) {
2383  $val = preg_replace('/\s/','',$val);
2384 // echo 'Element '.$val.' is a Function<br />';
2385  if (array_key_exists(strtoupper($matches[1]), $this->_controlFunctions) || array_key_exists(strtoupper($matches[1]), $this->_PHPExcelFunctions)) { // it's a func
2386  $stack->push(strtoupper($val));
2387  $ax = preg_match('/^\s*(\s*\))/i', substr($formula, $index+$length), $amatch);
2388  if ($ax) {
2389  $stack->push(0);
2390  $expectingOperator = true;
2391  } else {
2392  $stack->push(1);
2393  $expectingOperator = false;
2394  }
2395  $stack->push('(');
2396  } else { // it's a var w/ implicit multiplication
2397  $val = $matches[1];
2398  $output[] = $val;
2399  }
2400  } elseif (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $val, $matches)) {
2401 // echo 'Element '.$val.' is a Cell reference<br />';
2402 // Watch for this case-change when modifying to allow cell references in different worksheets...
2403 // Should only be applied to the actual cell column, not the worksheet name
2404 // $cellRef = strtoupper($val);
2405 // $output[] = $cellRef;
2406  $output[] = $val;
2407 // $expectingOperator = false;
2408  } else { // it's a variable, constant, string, number or boolean
2409 // echo 'Element is a Variable, Constant, String, Number or Boolean<br />';
2410  if ($opCharacter == '"') {
2411 // echo 'Element is a String<br />';
2412  $val = str_replace('""','"',$val);
2413  } elseif (is_numeric($val)) {
2414 // echo 'Element is a Number<br />';
2415  if ((strpos($val,'.') !== False) || (stripos($val,'e') !== False)) {
2416 // echo 'Casting '.$val.' to float<br />';
2417  $val = (float) $val;
2418  } else {
2419 // echo 'Casting '.$val.' to integer<br />';
2420  $val = (integer) $val;
2421  }
2422 // } elseif (array_key_exists(trim(strtoupper($val)), $this->_ExcelConstants)) {
2423 // $excelConstant = trim(strtoupper($val));
2424 // echo 'Element '.$val.' is an Excel Constant<br />';
2425 // $val = $this->_ExcelConstants[$excelConstant];
2426  }
2427  $output[] = $val;
2428  }
2429  $index += $length;
2430 
2431  } elseif ($opCharacter == ')') { // miscellaneous error checking
2432  if ($expectingOperand) {
2433  $output[] = $this->_ExcelConstants['NULL'];
2434  $expectingOperand = false;
2435  $expectingOperator = True;
2436  } else {
2437  return $this->_raiseFormulaError("Formula Error: Unexpected ')'");
2438  }
2439  } elseif (in_array($opCharacter, $this->_operators) && !$expectingOperator) {
2440  return $this->_raiseFormulaError("Formula Error: Unexpected operator '$opCharacter'");
2441  } else { // I don't even want to know what you did to get here
2442  return $this->_raiseFormulaError("Formula Error: An unexpected error occured");
2443  }
2444  // Test for end of formula string
2445  if ($index == strlen($formula)) {
2446  // Did we end with an operator?.
2447  // Only valid for the % unary operator
2448  if ((in_array($opCharacter, $this->_operators)) && ($opCharacter != '%')) {
2449  return $this->_raiseFormulaError("Formula Error: Operator '$opCharacter' has no operands");
2450  } else {
2451  break;
2452  }
2453  }
2454  // Ignore white space
2455  while (substr($formula, $index, 1) == ' ') {
2456  ++$index;
2457  }
2458  }
2459 
2460  while (!is_null($opCharacter = $stack->pop())) { // pop everything off the stack and push onto output
2461  if ($opCharacter == '(') return $this->_raiseFormulaError("Formula Error: Expecting ')'"); // if there are any opening braces on the stack, then braces were unbalanced
2462  $output[] = $opCharacter;
2463  }
2464  return $output;
2465  } // function _parseFormula()
2466 
2467 
2468  // evaluate postfix notation
2469  private function _processTokenStack($tokens, $cellID=null, PHPExcel_Cell $pCell = null) {
2470  if ($tokens == false) return false;
2471 
2472  $stack = new PHPExcel_Token_Stack;
2473 
2474  // Loop through each token in turn
2475  foreach ($tokens as $token) {
2476 // echo '<b>Token is '.$token.'</b><br />';
2477  // if the token is a binary operator, pop the top two values off the stack, do the operation, and push the result back on the stack
2478  if (in_array($token, $this->_binaryOperators, true)) {
2479 // echo 'Token is a binary operator<br />';
2480  // We must have two operands, error if we don't
2481  if (is_null($operand2 = $stack->pop())) return $this->_raiseFormulaError('Internal error - Operand value missing from stack');
2482  if (is_null($operand1 = $stack->pop())) return $this->_raiseFormulaError('Internal error - Operand value missing from stack');
2483  // Log what we're doing
2484  $this->_writeDebug($cellID,'Evaluating '.self::_showValue($operand1).' '.$token.' '.self::_showValue($operand2));
2485  // Process the operation in the appropriate manner
2486  switch ($token) {
2487  // Comparison (Boolean) Operators
2488  case '>' : // Greater than
2489  case '<' : // Less than
2490  case '>=' : // Greater than or Equal to
2491  case '<=' : // Less than or Equal to
2492  case '=' : // Equality
2493  case '<>' : // Inequality
2494  $this->_executeBinaryComparisonOperation($cellID,$operand1,$operand2,$token,$stack);
2495  break;
2496  // Binary Operators
2497  case '+' : // Addition
2498  $this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'plusEquals',$stack);
2499  break;
2500  case '-' : // Subtraction
2501  $this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'minusEquals',$stack);
2502  break;
2503  case '*' : // Multiplication
2504  $this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'arrayTimesEquals',$stack);
2505  break;
2506  case '/' : // Division
2507  $this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'arrayRightDivide',$stack);
2508  break;
2509  case '^' : // Exponential
2510  $this->_executeNumericBinaryOperation($cellID,$operand1,$operand2,$token,'power',$stack);
2511  break;
2512  case '&' : // Concatenation
2513  // If either of the operands is a matrix, we need to treat them both as matrices
2514  // (converting the other operand to a matrix if need be); then perform the required
2515  // matrix operation
2516  if ((is_array($operand1)) || (is_array($operand2))) {
2517  // Ensure that both operands are arrays/matrices
2518  self::_checkMatrixOperands($operand1,$operand2);
2519  try {
2520  // Convert operand 1 from a PHP array to a matrix
2521  $matrix = new Matrix($operand1);
2522  // Perform the required operation against the operand 1 matrix, passing in operand 2
2523  $matrixResult = $matrix->concat($operand2);
2524  $result = $matrixResult->getArray();
2525  } catch (Exception $ex) {
2526  $this->_writeDebug($cellID,'JAMA Matrix Exception: '.$ex->getMessage());
2527  $result = '#VALUE!';
2528  }
2529  } else {
2530  $result = '"'.str_replace('""','"',self::_unwrapResult($operand1,'"').self::_unwrapResult($operand2,'"')).'"';
2531  }
2532  $this->_writeDebug($cellID,'Evaluation Result is '.self::_showTypeDetails($result));
2533  $stack->push($result);
2534  break;
2535  }
2536 
2537  // if the token is a unary operator, pop one value off the stack, do the operation, and push it back on
2538  } elseif (($token === "_") || ($token === "%")) {
2539 // echo 'Token is a unary operator<br />';
2540  if (is_null($arg = $stack->pop())) return $this->_raiseFormulaError('Internal error - Operand value missing from stack');
2541  if ($token === "_") {
2542 // echo 'Token is a negation operator<br />';
2543  $this->_writeDebug($cellID,'Evaluating Negation of '.self::_showValue($arg));
2544  $multiplier = -1;
2545  } else {
2546 // echo 'Token is a percentile operator<br />';
2547  $this->_writeDebug($cellID,'Evaluating Percentile of '.self::_showValue($arg));
2548  $multiplier = 0.01;
2549  }
2550  if (is_array($arg)) {
2551  self::_checkMatrixOperands($arg,$multiplier);
2552  try {
2553  $matrix1 = new Matrix($arg);
2554  $matrixResult = $matrix1->arrayTimesEquals($multiplier);
2555  $result = $matrixResult->getArray();
2556  } catch (Exception $ex) {
2557  $this->_writeDebug($cellID,'JAMA Matrix Exception: '.$ex->getMessage());
2558  $result = '#VALUE!';
2559  }
2560 
2561  } else {
2562  $result = $multiplier * $arg;
2563  }
2564  $this->_writeDebug($cellID,'Evaluation Result is '.self::_showTypeDetails($result));
2565  $stack->push($result);
2566 
2567  } elseif (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $token, $matches)) {
2568 // echo 'Element '.$token.' is a Cell reference<br />';
2569  if (isset($matches[8])) {
2570 // echo 'Reference is a Range of cells<br />';
2571  if (is_null($pCell)) {
2572 // We can't access the range, so return a REF error
2573  $cellValue = PHPExcel_Calculation_Functions::REF();
2574  } else {
2575  $cellRef = $matches[6].$matches[7].':'.$matches[9].$matches[10];
2576  if ($matches[2] > '') {
2577 // echo '$cellRef='.$cellRef.' in worksheet '.$matches[2].'<br />';
2578  $this->_writeDebug($cellID,'Evaluating Cell Range '.$cellRef.' in worksheet '.$matches[2]);
2579  $cellValue = $this->extractCellRange($cellRef, $pCell->getParent()->getParent()->getSheetByName($matches[2]), false);
2580  $this->_writeDebug($cellID,'Evaluation Result for cells '.$cellRef.' in worksheet '.$matches[2].' is '.self::_showTypeDetails($cellValue));
2581  } else {
2582 // echo '$cellRef='.$cellRef.' in current worksheet<br />';
2583  $this->_writeDebug($cellID,'Evaluating Cell Range '.$cellRef.' in current worksheet');
2584  $cellValue = $this->extractCellRange($cellRef, $pCell->getParent(), false);
2585  $this->_writeDebug($cellID,'Evaluation Result for cells '.$cellRef.' is '.self::_showTypeDetails($cellValue));
2586  }
2587  }
2588  } else {
2589 // echo 'Reference is a single Cell<br />';
2590  if (is_null($pCell)) {
2591 // We can't access the cell, so return a REF error
2592  $cellValue = PHPExcel_Calculation_Functions::REF();
2593  } else {
2594  $cellRef = $matches[6].$matches[7];
2595  if ($matches[2] > '') {
2596 // echo '$cellRef='.$cellRef.' in worksheet '.$matches[2].'<br />';
2597  $this->_writeDebug($cellID,'Evaluating Cell '.$cellRef.' in worksheet '.$matches[2]);
2598  if ($pCell->getParent()->cellExists($cellRef)) {
2599  $cellValue = $this->extractCellRange($cellRef, $pCell->getParent()->getParent()->getSheetByName($matches[2]), false);
2600  } else {
2601  $cellValue = null;
2602  }
2603  $this->_writeDebug($cellID,'Evaluation Result for cell '.$cellRef.' in worksheet '.$matches[2].' is '.self::_showTypeDetails($cellValue));
2604  } else {
2605 // echo '$cellRef='.$cellRef.' in current worksheet<br />';
2606  $this->_writeDebug($cellID,'Evaluating Cell '.$cellRef.' in current worksheet');
2607  if ($pCell->getParent()->cellExists($cellRef)) {
2608  $cellValue = $pCell->getParent()->getCell($cellRef)->getCalculatedValue(false);
2609  } else {
2610  $cellValue = '';
2611  }
2612  $this->_writeDebug($cellID,'Evaluation Result for cell '.$cellRef.' is '.self::_showTypeDetails($cellValue));
2613  }
2614  }
2615  }
2616  $stack->push($cellValue);
2617 
2618  // if the token is a function, pop arguments off the stack, hand them to the function, and push the result back on
2619  } elseif (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $token, $matches)) {
2620 // echo 'Token is a function<br />';
2621  $functionName = $matches[1];
2622  $argCount = $stack->pop();
2623  if ($functionName != 'MKMATRIX') {
2624  $this->_writeDebug($cellID,'Evaluating Function '.$functionName.'() with '.(($argCount == 0) ? 'no' : $argCount).' argument'.(($argCount == 1) ? '' : 's'));
2625  }
2626  if ((array_key_exists($functionName, $this->_controlFunctions)) || (array_key_exists($functionName, $this->_PHPExcelFunctions))) { // function
2627  if (array_key_exists($functionName, $this->_controlFunctions)) {
2628  $functionCall = $this->_controlFunctions[$functionName]['functionCall'];
2629  } elseif (array_key_exists($functionName, $this->_PHPExcelFunctions)) {
2630  $functionCall = $this->_PHPExcelFunctions[$functionName]['functionCall'];
2631  }
2632  // get the arguments for this function
2633 // echo 'Function '.$functionName.' expects '.$argCount.' arguments<br />';
2634  $args = array();
2635  for ($i = $argCount; $i > 0; --$i) {
2636  $arg = $stack->pop();
2637 // if (is_null($arg)) return $this->_raiseFormulaError("internal error");
2638  $args[$i] = $arg;
2639  }
2640  // Reverse the order of the arguments
2641  ksort($args);
2642 // echo 'Arguments are: ';
2643 // print_r($args);
2644 // echo '<br />';
2645  if ($functionName != 'MKMATRIX') {
2646  $argArrayVals = array();
2647  foreach($args as &$arg) {
2648  $argArrayVals[] = self::_showValue($arg);
2649  $arg = self::_unwrapResult($arg);
2650  }
2651  unset($arg);
2652  $this->_writeDebug($cellID,'Evaluating '. $functionName.'( '.implode(', ',$argArrayVals).' )');
2653  }
2654  // Process each argument in turn, building the return value as an array
2655 // if (($argCount == 1) && (is_array($args[1])) && ($functionName != 'MKMATRIX')) {
2656 // $operand1 = $args[1];
2657 // $this->_writeDebug($cellID,'Argument is a matrix: '.self::_showValue($operand1));
2658 // $result = array();
2659 // $row = 0;
2660 // foreach($operand1 as $args) {
2661 // if (is_array($args)) {
2662 // foreach($args as $arg) {
2663 // $this->_writeDebug($cellID,'Evaluating '. $functionName.'( '.self::_showValue($arg).' )');
2664 // $r = call_user_func_array($functionCall,$arg);
2665 // $this->_writeDebug($cellID,'Evaluation Result is '.self::_showTypeDetails($r));
2666 // $result[$row][] = $r;
2667 // }
2668 // ++$row;
2669 // } else {
2670 // $this->_writeDebug($cellID,'Evaluating '. $functionName.'( '.self::_showValue($args).' )');
2671 // $r = call_user_func_array($functionCall,$args);
2672 // $this->_writeDebug($cellID,'Evaluation Result is '.self::_showTypeDetails($r));
2673 // $result[] = $r;
2674 // }
2675 // }
2676 // } else {
2677  // Process the argument with the appropriate function call
2678  $result = call_user_func_array($functionCall,$args);
2679 // }
2680  if ($functionName != 'MKMATRIX') {
2681  $this->_writeDebug($cellID,'Evaluation Result is '.self::_showTypeDetails($result));
2682  }
2683  $stack->push(self::_wrapResult($result));
2684  }
2685 
2686  } else {
2687  // if the token is a number, boolean, string or an Excel error, push it onto the stack
2688  if (array_key_exists(strtoupper($token), $this->_ExcelConstants)) {
2689  $excelConstant = strtoupper($token);
2690 // echo 'Token is a PHPExcel constant: '.$excelConstant.'<br />';
2691  $stack->push($this->_ExcelConstants[$excelConstant]);
2692  $this->_writeDebug($cellID,'Evaluating Constant '.$excelConstant.' as '.self::_showTypeDetails($this->_ExcelConstants[$excelConstant]));
2693  } elseif ((is_null($token)) || ($token == '') || (is_bool($token)) || (is_numeric($token)) || ($token{0} == '"') || ($token{0} == '#')) {
2694 // echo 'Token is a number, boolean, string or an Excel error<br />';
2695  $stack->push($token);
2696  // if the token is a constant, push the constant value on the stack
2697  } elseif (preg_match('/^'.self::CALCULATION_REGEXP_NAMEDRANGE.'$/i', $token, $matches)) {
2698 // echo 'Token is a named range<br />';
2699  $namedRange = $matches[6];
2700 // echo 'Named Range is '.$namedRange.'<br />';
2701  $this->_writeDebug($cellID,'Evaluating Named Range '.$namedRange);
2702  $cellValue = $this->extractNamedRange($namedRange, $pCell->getParent(), false);
2703  $this->_writeDebug($cellID,'Evaluation Result for named range '.$namedRange.' is '.self::_showTypeDetails($cellValue));
2704  $stack->push($cellValue);
2705  } else {
2706  return $this->_raiseFormulaError("undefined variable '$token'");
2707  }
2708  }
2709  }
2710  // when we're out of tokens, the stack should have a single element, the final result
2711  if ($stack->count() != 1) return $this->_raiseFormulaError("internal error");
2712  $output = $stack->pop();
2713  if ((is_array($output)) && (self::$returnArrayAsType != self::RETURN_ARRAY_AS_ARRAY)) {
2714  return array_unshift(array_unshift($output));
2715  }
2716  return $output;
2717  } // function _processTokenStack()
2718 
2719 
2720  private function _validateBinaryOperand($cellID,&$operand,&$stack) {
2721  // Numbers, matrices and booleans can pass straight through, as they're already valid
2722  if (is_string($operand)) {
2723  // We only need special validations for the operand if it is a string
2724  // Start by stripping off the quotation marks we use to identify true excel string values internally
2725  if ($operand > '' && $operand{0} == '"') { $operand = self::_unwrapResult($operand,'"'); }
2726  // If the string is a numeric value, we treat it as a numeric, so no further testing
2727  if (!is_numeric($operand)) {
2728  // If not a numeric, test to see if the value is an Excel error, and so can't be used in normal binary operations
2729  if ($operand > '' && $operand{0} == '#') {
2730  $stack->push($operand);
2731  $this->_writeDebug($cellID,'Evaluation Result is '.self::_showTypeDetails($operand));
2732  return false;
2733  } else {
2734  // If not a numeric, then it's a text string, and so can't be used in mathematical binary operations
2735  $stack->push('#VALUE!');
2736  $this->_writeDebug($cellID,'Evaluation Result is a '.self::_showTypeDetails('#VALUE!'));
2737  return false;
2738  }
2739  }
2740  }
2741 
2742  // return a true if the value of the operand is one that we can use in normal binary operations
2743  return true;
2744  } // function _validateBinaryOperand()
2745 
2746 
2747  private function _executeBinaryComparisonOperation($cellID,$operand1,$operand2,$operation,&$stack) {
2748  // Validate the two operands
2749 
2750  // If we're dealing with non-matrix operations, execute the necessary operation
2751  switch ($operation) {
2752  // Greater than
2753  case '>':
2754  $result = ($operand1 > $operand2);
2755  break;
2756  // Less than
2757  case '<':
2758  $result = ($operand1 < $operand2);
2759  break;
2760  // Equality
2761  case '=':
2762  $result = ($operand1 == $operand2);
2763  break;
2764  // Greater than or equal
2765  case '>=':
2766  $result = ($operand1 >= $operand2);
2767  break;
2768  // Less than or equal
2769  case '<=':
2770  $result = ($operand1 <= $operand2);
2771  break;
2772  // Inequality
2773  case '<>':
2774  $result = ($operand1 != $operand2);
2775  break;
2776  }
2777 
2778  // Log the result details
2779  $this->_writeDebug($cellID,'Evaluation Result is '.self::_showTypeDetails($result));
2780  // And push the result onto the stack
2781  $stack->push($result);
2782  return true;
2783  } // function _executeBinaryComparisonOperation()
2784 
2785  private function _executeNumericBinaryOperation($cellID,$operand1,$operand2,$operation,$matrixFunction,&$stack) {
2786  // Validate the two operands
2787  if (!$this->_validateBinaryOperand($cellID,$operand1,$stack)) return false;
2788  if (!$this->_validateBinaryOperand($cellID,$operand2,$stack)) return false;
2789 
2790  // If either of the operands is a matrix, we need to treat them both as matrices
2791  // (converting the other operand to a matrix if need be); then perform the required
2792  // matrix operation
2793  if ((is_array($operand1)) || (is_array($operand2))) {
2794  // Ensure that both operands are arrays/matrices
2795  self::_checkMatrixOperands($operand1,$operand2);
2796  try {
2797  // Convert operand 1 from a PHP array to a matrix
2798  $matrix = new Matrix($operand1);
2799  // Perform the required operation against the operand 1 matrix, passing in operand 2
2800  $matrixResult = $matrix->$matrixFunction($operand2);
2801  $result = $matrixResult->getArray();
2802  } catch (Exception $ex) {
2803  $this->_writeDebug($cellID,'JAMA Matrix Exception: '.$ex->getMessage());
2804  $result = '#VALUE!';
2805  }
2806  } else {
2807  // If we're dealing with non-matrix operations, execute the necessary operation
2808  switch ($operation) {
2809  // Addition
2810  case '+':
2811  $result = $operand1+$operand2;
2812  break;
2813  // Subtraction
2814  case '-':
2815  $result = $operand1-$operand2;
2816  break;
2817  // Multiplication
2818  case '*':
2819  $result = $operand1*$operand2;
2820  break;
2821  // Division
2822  case '/':
2823  if ($operand2 == 0) {
2824  // Trap for Divide by Zero error
2825  $stack->push('#DIV/0!');
2826  $this->_writeDebug($cellID,'Evaluation Result is '.self::_showTypeDetails('#DIV/0!'));
2827  return false;
2828  } else {
2829  $result = $operand1/$operand2;
2830  }
2831  break;
2832  // Power
2833  case '^':
2834  $result = pow($operand1,$operand2);
2835  break;
2836  }
2837  }
2838 
2839  // Log the result details
2840  $this->_writeDebug($cellID,'Evaluation Result is '.self::_showTypeDetails($result));
2841  // And push the result onto the stack
2842  $stack->push($result);
2843  return true;
2844  } // function _executeNumericBinaryOperation()
2845 
2846 
2847  private function _writeDebug($cellID,$message) {
2848  // Only write the debug log if logging is enabled
2849  if ($this->writeDebugLog) {
2850 // $prefix = substr(implode(' -> ',$this->debugLogStack).' -> ',4+strlen($this->debugLogStack[0]));
2851  $prefix = implode(' -> ',$this->debugLogStack).' -> ';
2852  $this->debugLog[] = $prefix.$message;
2853  }
2854  } // function _writeDebug()
2855 
2856 
2857  // trigger an error, but nicely, if need be
2858  private function _raiseFormulaError($errorMessage) {
2859  $this->formulaError = $errorMessage;
2860  if (!$this->suppressFormulaErrors) throw new Exception($errorMessage);
2861  trigger_error($errorMessage, E_USER_ERROR);
2862  } // function _raiseFormulaError()
2863 
2864 
2873  public function extractCellRange($pRange = 'A1', PHPExcel_Worksheet $pSheet = null, $resetLog=true) {
2874  // Return value
2875  $returnValue = array ( );
2876 
2877 // echo 'extractCellRange('.$pRange.')<br />';
2878  // Worksheet given?
2879  if (!is_null($pSheet)) {
2880  // Worksheet reference?
2881 // echo 'Current sheet name is '.$pSheet->getTitle().'<br />';
2882 // echo 'Range reference is '.$pRange.'<br />';
2883  if (strpos ($pRange, '!') !== false) {
2884 // echo '$pRange reference includes sheet reference<br />';
2885  $worksheetReference = PHPExcel_Worksheet::extractSheetTitle($pRange, true);
2886  $pSheet = $pSheet->getParent()->getSheetByName($worksheetReference[0]);
2887 // echo 'New sheet name is '.$pSheet->getTitle().'<br />';
2888  $pRange = $worksheetReference[1];
2889 // echo 'Adjusted Range reference is '.$pRange.'<br />';
2890  }
2891 
2892  // Extract range
2893  $aReferences = PHPExcel_Cell::extractAllCellReferencesInRange($pRange);
2894  if (count($aReferences) == 1) {
2895  return $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog);
2896  }
2897 
2898  // Extract cell data
2899  foreach ($aReferences as $reference) {
2900  // Extract range
2901  list($currentCol,$currentRow) = PHPExcel_Cell::coordinateFromString($reference);
2902 
2903  $returnValue[$currentCol][$currentRow] = $pSheet->getCell($reference)->getCalculatedValue($resetLog);
2904  }
2905  }
2906 
2907  // Return
2908  return $returnValue;
2909  } // function extractCellRange()
2910 
2911 
2920  public function extractNamedRange($pRange = 'A1', PHPExcel_Worksheet $pSheet = null, $resetLog=true) {
2921  // Return value
2922  $returnValue = array ( );
2923 
2924 // echo 'extractNamedRange('.$pRange.')<br />';
2925  // Worksheet given?
2926  if (!is_null($pSheet)) {
2927  // Worksheet reference?
2928 // echo 'Current sheet name is '.$pSheet->getTitle().'<br />';
2929 // echo 'Range reference is '.$pRange.'<br />';
2930  if (strpos ($pRange, '!') !== false) {
2931 // echo '$pRange reference includes sheet reference<br />';
2932  $worksheetReference = PHPExcel_Worksheet::extractSheetTitle($pRange, true);
2933  $pSheet = $pSheet->getParent()->getSheetByName($worksheetReference[0]);
2934 // echo 'New sheet name is '.$pSheet->getTitle().'<br />';
2935  $pRange = $worksheetReference[1];
2936 // echo 'Adjusted Range reference is '.$pRange.'<br />';
2937  }
2938 
2939  // Named range?
2940  $namedRange = PHPExcel_NamedRange::resolveRange($pRange, $pSheet);
2941  if (!is_null($namedRange)) {
2942 // echo 'Named Range '.$pRange.' (';
2943  $pRange = $namedRange->getRange();
2944 // echo $pRange.') is in sheet '.$namedRange->getWorksheet()->getTitle().'<br />';
2945  if ($pSheet->getTitle() != $namedRange->getWorksheet()->getTitle()) {
2946  if (!$namedRange->getLocalOnly()) {
2947  $pSheet = $namedRange->getWorksheet();
2948  } else {
2949  return $returnValue;
2950  }
2951  }
2952  }
2953 
2954  // Extract range
2955  $aReferences = PHPExcel_Cell::extractAllCellReferencesInRange($pRange);
2956  if (count($aReferences) == 1) {
2957  return $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog);
2958  }
2959 
2960  // Extract cell data
2961  foreach ($aReferences as $reference) {
2962  // Extract range
2963  list($currentCol,$currentRow) = PHPExcel_Cell::coordinateFromString($reference);
2964 // echo 'NAMED RANGE: $currentCol='.$currentCol.' $currentRow='.$currentRow.'<br />';
2965  $returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog);
2966  }
2967 // print_r($returnValue);
2968 // echo '<br />';
2969  $returnValue = array_values($returnValue);
2970  foreach($returnValue as &$rr) {
2971  $rr = array_values($rr);
2972  }
2973  unset($rr);
2974 // print_r($returnValue);
2975 // echo '<br />';
2976  }
2977 
2978  // Return
2979  return $returnValue;
2980  } // function extractNamedRange()
2981 
2982 
2989  public function isImplemented($pFunction = '') {
2990  $pFunction = strtoupper ($pFunction);
2991  if (isset ($this->_PHPExcelFunctions[$pFunction])) {
2992  return ($this->_PHPExcelFunctions[$pFunction]['functionCall'] != 'PHPExcel_Calculation_Functions::DUMMY');
2993  } else {
2994  return false;
2995  }
2996  } // function isImplemented()
2997 
2998 
3004  public function listFunctions() {
3005  // Return value
3006  $returnValue = array();
3007  // Loop functions
3008  foreach($this->_PHPExcelFunctions as $functionName => $function) {
3009  if ($function['functionCall'] != 'PHPExcel_Calculation_Functions::DUMMY') {
3010  $returnValue[$functionName] = new PHPExcel_Calculation_Function($function['category'],
3011  $functionName,
3012  $function['functionCall']
3013  );
3014  }
3015  }
3016 
3017  // Return
3018  return $returnValue;
3019  } // function listFunctions()
3020 
3021 
3027  public function listFunctionNames() {
3028  // Return value
3029  $returnValue = array();
3030  // Loop functions
3031  foreach ($this->_PHPExcelFunctions as $functionName => $function) {
3032  $returnValue[] = $functionName;
3033  }
3034 
3035  // Return
3036  return $returnValue;
3037  } // function listFunctionNames()
3038 
3039 } // class PHPExcel_Calculation
3040 
3041 
3042 
3043 
3044 // for internal use
3046 
3047  private $_stack = array();
3048  private $_count = 0;
3049 
3050  public function count() {
3051  return $this->_count;
3052  }
3053 
3054  public function push($value) {
3055  $this->_stack[$this->_count++] = $value;
3056  }
3057 
3058  public function pop() {
3059  if ($this->_count > 0) {
3060  return $this->_stack[--$this->_count];
3061  }
3062  return null;
3063  }
3064 
3065  public function last($n=1) {
3066  if ($this->_count-$n < 0) {
3067  return null;
3068  }
3069  return $this->_stack[$this->_count-$n];
3070  }
3071 
3072  function __construct() {
3073  }
3074 
3075 } // class PHPExcel_Token_Stack