Formula.pm 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513
  1. # DISCLAIMER OF WARRANTY
  2. # Because this software is licensed free of charge, there is no warranty for the software,
  3. # to the extent permitted by applicable law. Except when otherwise stated in writing
  4. # the copyright holders and/or other parties provide the software "as is" without
  5. # warranty of any kind, either expressed or implied, including, but not limited to,
  6. # the implied warranties of merchantability and fitness for a particular purpose.
  7. # The entire risk as to the quality and performance of the software is with you.
  8. # Should the software prove defective, you assume the cost of all necessary
  9. # servicing, repair, or correction.
  10. # In no event unless required by applicable law or agreed to in writing will any
  11. # copyright holder, or any other party who may modify and/or redistribute the software
  12. # as permitted by the above licence, be liable to you for damages, including any general,
  13. # special, incidental, or consequential damages arising out of the use or inability
  14. # to use the software (including but not limited to loss of data or data being rendered
  15. # inaccurate or losses sustained by you or third parties or a failure of the software
  16. # to operate with any other software), even if such holder or other party
  17. # has been advised of the possibility of such damages.
  18. # AUTHOR
  19. # John McNamara jmcnamara@cpan.org
  20. # COPYRIGHT
  21. # Copyright MM-MMX, John McNamara.
  22. # All Rights Reserved. This module is free software. It may be used,
  23. # redistributed and/or modified under the terms of
  24. # the Artistic License(full text of the Artistic License http://dev.perl.org/licenses/artistic.html).
  25. package Spreadsheet::WriteExcel::Formula;
  26. ###############################################################################
  27. #
  28. # Formula - A class for generating Excel formulas.
  29. #
  30. #
  31. # Used in conjunction with Spreadsheet::WriteExcel
  32. #
  33. # Copyright 2000-2010, John McNamara, jmcnamara@cpan.org
  34. #
  35. # Documentation after __END__
  36. #
  37. use Exporter;
  38. use strict;
  39. use Carp;
  40. use vars qw($VERSION @ISA);
  41. @ISA = qw(Exporter);
  42. $VERSION = '2.37';
  43. ###############################################################################
  44. #
  45. # Class data.
  46. #
  47. my $parser;
  48. my %ptg;
  49. my %functions;
  50. ###############################################################################
  51. #
  52. # For debugging.
  53. #
  54. my $_debug = 0;
  55. ###############################################################################
  56. #
  57. # new()
  58. #
  59. # Constructor
  60. #
  61. sub new {
  62. my $class = $_[0];
  63. my $self = {
  64. _byte_order => $_[1],
  65. _workbook => "",
  66. _ext_sheets => {},
  67. _ext_refs => {},
  68. _ext_ref_count => 0,
  69. _ext_names => {},
  70. };
  71. bless $self, $class;
  72. return $self;
  73. }
  74. ###############################################################################
  75. #
  76. # _init_parser()
  77. #
  78. # There is a small overhead involved in generating the parser. Therefore, the
  79. # initialisation is delayed until a formula is required.
  80. # TODO: use a pre-compiled grammar.
  81. #
  82. # Porters take note, a recursive descent parser isn't mandatory. A future
  83. # version of this module may use a YACC based parser instead.
  84. #
  85. sub _init_parser {
  86. my $self = shift;
  87. # Delay loading Parse::RecDescent to reduce the module dependencies.
  88. eval { require Parse::RecDescent };
  89. die "The Parse::RecDescent module must be installed in order ".
  90. "to write an Excel formula\n" if $@;
  91. $self->_initialize_hashes();
  92. # The parsing grammar.
  93. #
  94. # TODO: Add support for international versions of Excel
  95. #
  96. $parser = Parse::RecDescent->new(<<'EndGrammar');
  97. expr: list
  98. # Match arg lists such as SUM(1,2, 3)
  99. list: <leftop: addition ',' addition>
  100. { [ $item[1], '_arg', scalar @{$item[1]} ] }
  101. addition: <leftop: multiplication add_op multiplication>
  102. # TODO: The add_op operators don't have equal precedence.
  103. add_op: add | sub | concat
  104. | eq | ne | le | ge | lt | gt # Order is important
  105. add: '+' { 'ptgAdd' }
  106. sub: '-' { 'ptgSub' }
  107. concat: '&' { 'ptgConcat' }
  108. eq: '=' { 'ptgEQ' }
  109. ne: '<>' { 'ptgNE' }
  110. le: '<=' { 'ptgLE' }
  111. ge: '>=' { 'ptgGE' }
  112. lt: '<' { 'ptgLT' }
  113. gt: '>' { 'ptgGT' }
  114. multiplication: <leftop: exponention mult_op exponention>
  115. mult_op: mult | div
  116. mult: '*' { 'ptgMul' }
  117. div: '/' { 'ptgDiv' }
  118. # Left associative (apparently)
  119. exponention: <leftop: factor exp_op factor>
  120. exp_op: '^' { 'ptgPower' }
  121. factor: number # Order is important
  122. | string
  123. | range2d
  124. | range3d
  125. | true
  126. | false
  127. | ref2d
  128. | ref3d
  129. | function
  130. | name
  131. | '(' expr ')' { [$item[2], 'ptgParen'] }
  132. # Match a string.
  133. # Regex by merlyn. See http://www.perlmonks.org/index.pl?node_id=330280
  134. #
  135. string: /"([^"]|"")*"/ #" For editors
  136. { [ '_str', $item[1]] }
  137. # Match float or integer
  138. number: /([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?/
  139. { ['_num', $item[1]] }
  140. # Note: The highest column values is IV. The following regexes match
  141. # up to IZ. Out of range values are caught in the code.
  142. #
  143. # Note: sheetnames with whitespace, commas, or parentheses must be in
  144. # single quotes. Applies to ref3d and range3d
  145. #
  146. # Match A1, $A1, A$1 or $A$1.
  147. ref2d: /\$?[A-I]?[A-Z]\$?\d+/
  148. { ['_ref2d', $item[1]] }
  149. # Match an external sheet reference: Sheet1!A1 or 'Sheet (1)'!A1
  150. ref3d: /[^!(,]+!\$?[A-I]?[A-Z]\$?\d+/
  151. { ['_ref3d', $item[1]] }
  152. | /'[^']+'!\$?[A-I]?[A-Z]\$?\d+/
  153. { ['_ref3d', $item[1]] }
  154. # Match A1:C5, $A1:$C5 or A:C etc.
  155. range2d: /\$?[A-I]?[A-Z]\$?(\d+)?:\$?[A-I]?[A-Z]\$?(\d+)?/
  156. { ['_range2d', $item[1]] }
  157. # Match an external sheet range. 'Sheet 1:Sheet 2'!B2:C5
  158. range3d: /[^!(,]+!\$?[A-I]?[A-Z]\$?(\d+)?:\$?[A-I]?[A-Z]\$?(\d+)?/
  159. { ['_range3d', $item[1]] }
  160. | /'[^']+'!\$?[A-I]?[A-Z]\$?(\d+)?:\$?[A-I]?[A-Z]\$?(\d+)?/
  161. { ['_range3d', $item[1]] }
  162. # Match a function name.
  163. function: /[A-Z0-9À-Ü_.]+/ '()'
  164. { ['_func', $item[1]] }
  165. | /[A-Z0-9À-Ü_.]+/ '(' expr ')'
  166. { ['_class', $item[1], $item[3], '_func', $item[1]] }
  167. | /[A-Z0-9À-Ü_.]+/ '(' list ')'
  168. { ['_class', $item[1], $item[3], '_func', $item[1]] }
  169. # Match a defined name.
  170. name: /[A-Za-z_]\w+/
  171. { ['_name', $item[1]] }
  172. # Boolean values.
  173. true: 'TRUE' { [ 'ptgBool', 1 ] }
  174. false: 'FALSE' { [ 'ptgBool', 0 ] }
  175. EndGrammar
  176. print "Init_parser.\n\n" if $_debug;
  177. }
  178. ###############################################################################
  179. #
  180. # parse_formula()
  181. #
  182. # Takes a textual description of a formula and returns a RPN encoded byte
  183. # string.
  184. #
  185. sub parse_formula {
  186. my $self= shift;
  187. # Initialise the parser if this is the first call
  188. $self->_init_parser() if not defined $parser;
  189. my $formula = shift @_;
  190. my $tokens;
  191. print $formula, "\n" if $_debug;
  192. # Build the parse tree for the formula
  193. my $parsetree =$parser->expr($formula);
  194. # Check if parsing worked.
  195. if (defined $parsetree) {
  196. my @tokens = $self->_reverse_tree(@$parsetree);
  197. # Add a volatile token if the formula contains a volatile function.
  198. # This must be the first token in the list
  199. #
  200. unshift @tokens, '_vol' if $self->_check_volatile(@tokens);
  201. # The return value depends on which Worksheet.pm method is the caller
  202. if (wantarray) {
  203. # Parse formula to see if it throws any errors and then
  204. # return raw tokens to Worksheet::store_formula()
  205. #
  206. $self->parse_tokens(@tokens);
  207. return @tokens;
  208. }
  209. else{
  210. # Return byte stream to Worksheet::write_formula()
  211. return $self->parse_tokens(@tokens);
  212. }
  213. }
  214. else {
  215. die "Couldn't parse formula: =$formula\n";
  216. }
  217. }
  218. ###############################################################################
  219. #
  220. # parse_tokens()
  221. #
  222. # Convert each token or token pair to its Excel 'ptg' equivalent.
  223. #
  224. sub parse_tokens {
  225. my $self = shift;
  226. my $parse_str = '';
  227. my $last_type = '';
  228. my $modifier = '';
  229. my $num_args = 0;
  230. my $class = 0;
  231. my @class = 1;
  232. my @tokens = @_;
  233. # A note about the class modifiers used below. In general the class,
  234. # "reference" or "value", of a function is applied to all of its operands.
  235. # However, in certain circumstances the operands can have mixed classes,
  236. # e.g. =VLOOKUP with external references. These will eventually be dealt
  237. # with by the parser. However, as a workaround the class type of a token
  238. # can be changed via the repeat_formula interface. Thus, a _ref2d token can
  239. # be changed by the user to _ref2dA or _ref2dR to change its token class.
  240. #
  241. while (@_) {
  242. my $token = shift @_;
  243. if ($token eq '_arg') {
  244. $num_args = shift @_;
  245. }
  246. elsif ($token eq '_class') {
  247. $token = shift @_;
  248. $class = $functions{$token}[2];
  249. # If $class is undef then it means that the function isn't valid.
  250. die "Unknown function $token() in formula\n" unless defined $class;
  251. push @class, $class;
  252. }
  253. elsif ($token eq '_vol') {
  254. $parse_str .= $self->_convert_volatile();
  255. }
  256. elsif ($token eq 'ptgBool') {
  257. $token = shift @_;
  258. $parse_str .= $self->_convert_bool($token);
  259. }
  260. elsif ($token eq '_num') {
  261. $token = shift @_;
  262. $parse_str .= $self->_convert_number($token);
  263. }
  264. elsif ($token eq '_str') {
  265. $token = shift @_;
  266. $parse_str .= $self->_convert_string($token);
  267. }
  268. elsif ($token =~ /^_ref2d/) {
  269. ($modifier = $token) =~ s/_ref2d//;
  270. $class = $class[-1];
  271. $class = 0 if $modifier eq 'R';
  272. $class = 1 if $modifier eq 'V';
  273. $token = shift @_;
  274. $parse_str .= $self->_convert_ref2d($token, $class);
  275. }
  276. elsif ($token =~ /^_ref3d/) {
  277. ($modifier = $token) =~ s/_ref3d//;
  278. $class = $class[-1];
  279. $class = 0 if $modifier eq 'R';
  280. $class = 1 if $modifier eq 'V';
  281. $token = shift @_;
  282. $parse_str .= $self->_convert_ref3d($token, $class);
  283. }
  284. elsif ($token =~ /^_range2d/) {
  285. ($modifier = $token) =~ s/_range2d//;
  286. $class = $class[-1];
  287. $class = 0 if $modifier eq 'R';
  288. $class = 1 if $modifier eq 'V';
  289. $token = shift @_;
  290. $parse_str .= $self->_convert_range2d($token, $class);
  291. }
  292. elsif ($token =~ /^_range3d/) {
  293. ($modifier = $token) =~ s/_range3d//;
  294. $class = $class[-1];
  295. $class = 0 if $modifier eq 'R';
  296. $class = 1 if $modifier eq 'V';
  297. $token = shift @_;
  298. $parse_str .= $self->_convert_range3d($token, $class);
  299. }
  300. elsif ($token =~ /^_name/) {
  301. ($modifier = $token) =~ s/_name//;
  302. $class = $class[-1];
  303. $class = 0 if $modifier eq 'R';
  304. $class = 1 if $modifier eq 'V';
  305. $token = shift @_;
  306. $parse_str .= $self->_convert_name($token, $class);
  307. }
  308. elsif ($token eq '_func') {
  309. $token = shift @_;
  310. $parse_str .= $self->_convert_function($token, $num_args);
  311. pop @class;
  312. $num_args = 0; # Reset after use
  313. }
  314. elsif (exists $ptg{$token}) {
  315. $parse_str .= pack("C", $ptg{$token});
  316. }
  317. else {
  318. # Unrecognised token
  319. return undef;
  320. }
  321. }
  322. if ($_debug) {
  323. print join(" ", map { sprintf "%02X", $_ } unpack("C*",$parse_str));
  324. print "\n\n";
  325. print join(" ", @tokens), "\n\n";
  326. }
  327. return $parse_str;
  328. }
  329. ###############################################################################
  330. #
  331. # _reverse_tree()
  332. #
  333. # This function descends recursively through the parse tree. At each level it
  334. # swaps the order of an operator followed by an operand.
  335. # For example, 1+2*3 would be converted in the following sequence:
  336. # 1 + 2 * 3
  337. # 1 + (2 * 3)
  338. # 1 + (2 3 *)
  339. # 1 (2 3 *) +
  340. # 1 2 3 * +
  341. #
  342. sub _reverse_tree
  343. {
  344. my $self = shift;
  345. my @tokens;
  346. my @expression = @_;
  347. my @stack;
  348. while (@expression) {
  349. my $token = shift @expression;
  350. # If the token is an operator swap it with the following operand
  351. if ( $token eq 'ptgAdd' ||
  352. $token eq 'ptgSub' ||
  353. $token eq 'ptgConcat' ||
  354. $token eq 'ptgMul' ||
  355. $token eq 'ptgDiv' ||
  356. $token eq 'ptgPower' ||
  357. $token eq 'ptgEQ' ||
  358. $token eq 'ptgNE' ||
  359. $token eq 'ptgLE' ||
  360. $token eq 'ptgGE' ||
  361. $token eq 'ptgLT' ||
  362. $token eq 'ptgGT')
  363. {
  364. my $operand = shift @expression;
  365. push @stack, $operand;
  366. }
  367. push @stack, $token;
  368. }
  369. # Recurse through the parse tree
  370. foreach my $token (@stack) {
  371. if (ref($token)) {
  372. push @tokens, $self->_reverse_tree(@$token);
  373. }
  374. else {
  375. push @tokens, $token;
  376. }
  377. }
  378. return @tokens;
  379. }
  380. ###############################################################################
  381. #
  382. # _check_volatile()
  383. #
  384. # Check if the formula contains a volatile function, i.e. a function that must
  385. # be recalculated each time a cell is updated. These formulas require a ptgAttr
  386. # with the volatile flag set as the first token in the parsed expression.
  387. #
  388. # Examples of volatile functions: RAND(), NOW(), TODAY()
  389. #
  390. sub _check_volatile {
  391. my $self = shift;
  392. my @tokens = @_;
  393. my $volatile = 0;
  394. for my $i (0..@tokens-1) {
  395. # If the next token is a function check if it is volatile.
  396. if ($tokens[$i] eq '_func' and $functions{$tokens[$i+1]}[3]) {
  397. $volatile = 1;
  398. last;
  399. }
  400. }
  401. return $volatile;
  402. }
  403. ###############################################################################
  404. #
  405. # _convert_volatile()
  406. #
  407. # Convert _vol to a ptgAttr tag formatted to indicate that the formula contains
  408. # a volatile function. See _check_volatile()
  409. #
  410. sub _convert_volatile {
  411. my $self = shift;
  412. # Set bitFattrSemi flag to indicate volatile function, "w" is set to zero.
  413. return pack("CCv", $ptg{ptgAttr}, 0x1, 0x0);
  414. }
  415. ###############################################################################
  416. #
  417. # _convert_bool()
  418. #
  419. # Convert a boolean token to ptgBool
  420. #
  421. sub _convert_bool {
  422. my $self = shift;
  423. my $bool = shift;
  424. return pack("CC", $ptg{ptgBool}, $bool);
  425. }
  426. ###############################################################################
  427. #
  428. # _convert_number()
  429. #
  430. # Convert a number token to ptgInt or ptgNum
  431. #
  432. sub _convert_number {
  433. my $self = shift;
  434. my $num = shift;
  435. # Integer in the range 0..2**16-1
  436. if (($num =~ /^\d+$/) && ($num <= 65535)) {
  437. return pack("Cv", $ptg{ptgInt}, $num);
  438. }
  439. else { # A float
  440. $num = pack("d", $num);
  441. $num = reverse $num if $self->{_byte_order};
  442. return pack("C", $ptg{ptgNum}) . $num;
  443. }
  444. }
  445. ###############################################################################
  446. #
  447. # _convert_string()
  448. #
  449. # Convert a string to a ptg Str.
  450. #
  451. sub _convert_string {
  452. my $self = shift;
  453. my $str = shift;
  454. my $encoding = 0;
  455. $str =~ s/^"//; # Remove leading "
  456. $str =~ s/"$//; # Remove trailing "
  457. $str =~ s/""/"/g; # Substitute Excel's escaped double quote "" for "
  458. my $length = length($str);
  459. # Handle utf8 strings in perl 5.8.
  460. if ($] >= 5.008) {
  461. require Encode;
  462. if (Encode::is_utf8($str)) {
  463. $str = Encode::encode("UTF-16LE", $str);
  464. $encoding = 1;
  465. }
  466. }
  467. die "String in formula has more than 255 chars\n" if $length > 255;
  468. return pack("CCC", $ptg{ptgStr}, $length, $encoding) . $str;
  469. }
  470. ###############################################################################
  471. #
  472. # _convert_ref2d()
  473. #
  474. # Convert an Excel reference such as A1, $B2, C$3 or $D$4 to a ptgRefV.
  475. #
  476. sub _convert_ref2d {
  477. my $self = shift;
  478. my $cell = shift;
  479. my $class = shift;
  480. my $ptgRef;
  481. # Convert the cell reference
  482. my ($row, $col) = $self->_cell_to_packed_rowcol($cell);
  483. # The ptg value depends on the class of the ptg.
  484. if ($class == 0) {
  485. $ptgRef = pack("C", $ptg{ptgRef});
  486. }
  487. elsif ($class == 1) {
  488. $ptgRef = pack("C", $ptg{ptgRefV});
  489. }
  490. elsif ($class == 2) {
  491. $ptgRef = pack("C", $ptg{ptgRefA});
  492. }
  493. else{
  494. die "Unknown function class in formula\n";
  495. }
  496. return $ptgRef . $row . $col;
  497. }
  498. ###############################################################################
  499. #
  500. # _convert_ref3d
  501. #
  502. # Convert an Excel 3d reference such as "Sheet1!A1" or "Sheet1:Sheet2!A1" to a
  503. # ptgRef3dV.
  504. #
  505. sub _convert_ref3d {
  506. my $self = shift;
  507. my $token = shift;
  508. my $class = shift;
  509. my $ptgRef;
  510. # Split the ref at the ! symbol
  511. my ($ext_ref, $cell) = split '!', $token;
  512. # Convert the external reference part
  513. $ext_ref = $self->_pack_ext_ref($ext_ref);
  514. # Convert the cell reference part
  515. my ($row, $col) = $self->_cell_to_packed_rowcol($cell);
  516. # The ptg value depends on the class of the ptg.
  517. if ($class == 0) {
  518. $ptgRef = pack("C", $ptg{ptgRef3d});
  519. }
  520. elsif ($class == 1) {
  521. $ptgRef = pack("C", $ptg{ptgRef3dV});
  522. }
  523. elsif ($class == 2) {
  524. $ptgRef = pack("C", $ptg{ptgRef3dA});
  525. }
  526. else{
  527. die "Unknown function class in formula\n";
  528. }
  529. return $ptgRef . $ext_ref. $row . $col;
  530. }
  531. ###############################################################################
  532. #
  533. # _convert_range2d()
  534. #
  535. # Convert an Excel range such as A1:D4 or A:D to a ptgRefV.
  536. #
  537. sub _convert_range2d {
  538. my $self = shift;
  539. my $range = shift;
  540. my $class = shift;
  541. my $ptgArea;
  542. # Split the range into 2 cell refs
  543. my ($cell1, $cell2) = split ':', $range;
  544. # A range such as A:D is equivalent to A1:D65536, so add rows as required
  545. $cell1 .= '1' if $cell1 !~ /\d/;
  546. $cell2 .= '65536' if $cell2 !~ /\d/;
  547. # Convert the cell references
  548. my ($row1, $col1) = $self->_cell_to_packed_rowcol($cell1);
  549. my ($row2, $col2) = $self->_cell_to_packed_rowcol($cell2);
  550. # The ptg value depends on the class of the ptg.
  551. if ($class == 0) {
  552. $ptgArea = pack("C", $ptg{ptgArea});
  553. }
  554. elsif ($class == 1) {
  555. $ptgArea = pack("C", $ptg{ptgAreaV});
  556. }
  557. elsif ($class == 2) {
  558. $ptgArea = pack("C", $ptg{ptgAreaA});
  559. }
  560. else{
  561. die "Unknown function class in formula\n";
  562. }
  563. return $ptgArea . $row1 . $row2 . $col1. $col2;
  564. }
  565. ###############################################################################
  566. #
  567. # _convert_range3d
  568. #
  569. # Convert an Excel 3d range such as "Sheet1!A1:D4" or "Sheet1:Sheet2!A1:D4" to
  570. # a ptgArea3dV.
  571. #
  572. sub _convert_range3d {
  573. my $self = shift;
  574. my $token = shift;
  575. my $class = shift;
  576. my $ptgArea;
  577. # Split the ref at the ! symbol
  578. my ($ext_ref, $range) = split '!', $token;
  579. # Convert the external reference part
  580. $ext_ref = $self->_pack_ext_ref($ext_ref);
  581. # Split the range into 2 cell refs
  582. my ($cell1, $cell2) = split ':', $range;
  583. # A range such as A:D is equivalent to A1:D65536, so add rows as required
  584. $cell1 .= '1' if $cell1 !~ /\d/;
  585. $cell2 .= '65536' if $cell2 !~ /\d/;
  586. # Convert the cell references
  587. my ($row1, $col1) = $self->_cell_to_packed_rowcol($cell1);
  588. my ($row2, $col2) = $self->_cell_to_packed_rowcol($cell2);
  589. # The ptg value depends on the class of the ptg.
  590. if ($class == 0) {
  591. $ptgArea = pack("C", $ptg{ptgArea3d});
  592. }
  593. elsif ($class == 1) {
  594. $ptgArea = pack("C", $ptg{ptgArea3dV});
  595. }
  596. elsif ($class == 2) {
  597. $ptgArea = pack("C", $ptg{ptgArea3dA});
  598. }
  599. else{
  600. die "Unknown function class in formula\n";
  601. }
  602. return $ptgArea . $ext_ref . $row1 . $row2 . $col1. $col2;
  603. }
  604. ###############################################################################
  605. #
  606. # _pack_ext_ref()
  607. #
  608. # Convert the sheet name part of an external reference, for example "Sheet1" or
  609. # "Sheet1:Sheet2", to a packed structure.
  610. #
  611. sub _pack_ext_ref {
  612. my $self = shift;
  613. my $ext_ref = shift;
  614. my $sheet1;
  615. my $sheet2;
  616. $ext_ref =~ s/^'//; # Remove leading ' if any.
  617. $ext_ref =~ s/'$//; # Remove trailing ' if any.
  618. # Check if there is a sheet range eg., Sheet1:Sheet2.
  619. if ($ext_ref =~ /:/) {
  620. ($sheet1, $sheet2) = split ':', $ext_ref;
  621. $sheet1 = $self->_get_sheet_index($sheet1);
  622. $sheet2 = $self->_get_sheet_index($sheet2);
  623. # Reverse max and min sheet numbers if necessary
  624. if ($sheet1 > $sheet2) {
  625. ($sheet1, $sheet2) = ($sheet2, $sheet1);
  626. }
  627. }
  628. else {
  629. # Single sheet name only.
  630. ($sheet1, $sheet2) = ($ext_ref, $ext_ref);
  631. $sheet1 = $self->_get_sheet_index($sheet1);
  632. $sheet2 = $sheet1;
  633. }
  634. my $key = "$sheet1:$sheet2";
  635. my $index;
  636. if (exists $self->{_ext_refs}->{$key}) {
  637. $index = $self->{_ext_refs}->{$key};
  638. }
  639. else {
  640. $index = $self->{_ext_ref_count};
  641. $self->{_ext_refs}->{$key} = $index;
  642. $self->{_ext_ref_count}++;
  643. }
  644. return pack("v",$index);
  645. }
  646. ###############################################################################
  647. #
  648. # _get_sheet_index()
  649. #
  650. # Look up the index that corresponds to an external sheet name. The hash of
  651. # sheet names is updated by the add_worksheet() method of the Workbook class.
  652. #
  653. sub _get_sheet_index {
  654. my $self = shift;
  655. my $sheet_name = shift;
  656. # Handle utf8 sheetnames in perl 5.8.
  657. if ($] >= 5.008) {
  658. require Encode;
  659. if (Encode::is_utf8($sheet_name)) {
  660. $sheet_name = Encode::encode("UTF-16BE", $sheet_name);
  661. }
  662. }
  663. if (not exists $self->{_ext_sheets}->{$sheet_name}) {
  664. die "Unknown sheet name $sheet_name in formula\n";
  665. }
  666. else {
  667. return $self->{_ext_sheets}->{$sheet_name};
  668. }
  669. }
  670. ###############################################################################
  671. #
  672. # set_ext_sheets()
  673. #
  674. # This semi-public method is used to update the hash of sheet names. It is
  675. # updated by the add_worksheet() method of the Workbook class.
  676. #
  677. sub set_ext_sheets {
  678. my $self = shift;
  679. my $worksheet = shift;
  680. my $index = shift;
  681. # The _ext_sheets hash is used to translate between worksheet names
  682. # and their index
  683. $self->{_ext_sheets}->{$worksheet} = $index;
  684. }
  685. ###############################################################################
  686. #
  687. # get_ext_sheets()
  688. #
  689. # This semi-public method is used to get the worksheet references that were
  690. # used in formulas for inclusion in the EXTERNSHEET Workbook record.
  691. #
  692. sub get_ext_sheets {
  693. my $self = shift;
  694. return %{$self->{_ext_refs}};
  695. }
  696. ###############################################################################
  697. #
  698. # get_ext_ref_count()
  699. #
  700. # This semi-public method is used to update the hash of sheet names. It is
  701. # updated by the add_worksheet() method of the Workbook class.
  702. #
  703. sub get_ext_ref_count {
  704. my $self = shift;
  705. return $self->{_ext_ref_count};
  706. }
  707. ###############################################################################
  708. #
  709. # _get_name_index()
  710. #
  711. # Look up the index that corresponds to an external defined name. The hash of
  712. # defined names is updated by the define_name() method in the Workbook class.
  713. #
  714. sub _get_name_index {
  715. my $self = shift;
  716. my $name = shift;
  717. if (not exists $self->{_ext_names}->{$name}) {
  718. die "Unknown defined name $name in formula\n";
  719. }
  720. else {
  721. return $self->{_ext_names}->{$name};
  722. }
  723. }
  724. ###############################################################################
  725. #
  726. # set_ext_name()
  727. #
  728. # This semi-public method is used to update the hash of defined names.
  729. #
  730. sub set_ext_name {
  731. my $self = shift;
  732. my $name = shift;
  733. my $index = shift;
  734. $self->{_ext_names}->{$name} = $index;
  735. }
  736. ###############################################################################
  737. #
  738. # _convert_function()
  739. #
  740. # Convert a function to a ptgFunc or ptgFuncVarV depending on the number of
  741. # args that it takes.
  742. #
  743. sub _convert_function {
  744. my $self = shift;
  745. my $token = shift;
  746. my $num_args = shift;
  747. die "Unknown function $token() in formula\n"
  748. unless defined $functions{$token}[0];
  749. my $args = $functions{$token}[1];
  750. # Fixed number of args eg. TIME($i,$j,$k).
  751. if ($args >= 0) {
  752. # Check that the number of args is valid.
  753. if ($args != $num_args) {
  754. die "Incorrect number of arguments for $token() in formula\n";
  755. }
  756. else {
  757. return pack("Cv", $ptg{ptgFuncV}, $functions{$token}[0]);
  758. }
  759. }
  760. # Variable number of args eg. SUM($i,$j,$k, ..).
  761. if ($args == -1) {
  762. return pack "CCv", $ptg{ptgFuncVarV}, $num_args, $functions{$token}[0];
  763. }
  764. }
  765. ###############################################################################
  766. #
  767. # _convert_name()
  768. #
  769. # Convert a symbolic name into a name reference.
  770. #
  771. sub _convert_name {
  772. my $self = shift;
  773. my $name = shift;
  774. my $class = shift;
  775. my $ptgName;
  776. my $name_index = $self->_get_name_index($name);
  777. # The ptg value depends on the class of the ptg.
  778. if ($class == 0) {
  779. $ptgName = $ptg{ptgName};
  780. }
  781. elsif ($class == 1) {
  782. $ptgName = $ptg{ptgNameV};
  783. }
  784. elsif ($class == 2) {
  785. $ptgName = $ptg{ptgNameA};
  786. }
  787. return pack 'CV', $ptgName, $name_index;
  788. }
  789. ###############################################################################
  790. #
  791. # _cell_to_rowcol($cell_ref)
  792. #
  793. # Convert an Excel cell reference such as A1 or $B2 or C$3 or $D$4 to a zero
  794. # indexed row and column number. Also returns two boolean values to indicate
  795. # whether the row or column are relative references.
  796. # TODO use function in Utility.pm
  797. #
  798. sub _cell_to_rowcol {
  799. my $self = shift;
  800. my $cell = shift;
  801. $cell =~ /(\$?)([A-I]?[A-Z])(\$?)(\d+)/;
  802. my $col_rel = $1 eq "" ? 1 : 0;
  803. my $col = $2;
  804. my $row_rel = $3 eq "" ? 1 : 0;
  805. my $row = $4;
  806. # Convert base26 column string to a number.
  807. # All your Base are belong to us.
  808. my @chars = split //, $col;
  809. my $expn = 0;
  810. $col = 0;
  811. while (@chars) {
  812. my $char = pop(@chars); # LS char first
  813. $col += (ord($char) - ord('A') + 1) * (26**$expn);
  814. $expn++;
  815. }
  816. # Convert 1-index to zero-index
  817. $row--;
  818. $col--;
  819. return $row, $col, $row_rel, $col_rel;
  820. }
  821. ###############################################################################
  822. #
  823. # _cell_to_packed_rowcol($row, $col, $row_rel, $col_rel)
  824. #
  825. # pack() row and column into the required 3 byte format.
  826. #
  827. sub _cell_to_packed_rowcol {
  828. use integer; # Avoid << shift bug in Perl 5.6.0 on HP-UX
  829. my $self = shift;
  830. my $cell = shift;
  831. my ($row, $col, $row_rel, $col_rel) = $self->_cell_to_rowcol($cell);
  832. die "Column $cell greater than IV in formula\n" if $col >= 256;
  833. die "Row $cell greater than 65536 in formula\n" if $row >= 65536;
  834. # Set the high bits to indicate if row or col are relative.
  835. $col |= $col_rel << 14;
  836. $col |= $row_rel << 15;
  837. $row = pack('v', $row);
  838. $col = pack('v', $col);
  839. return ($row, $col);
  840. }
  841. ###############################################################################
  842. #
  843. # _initialize_hashes()
  844. #
  845. sub _initialize_hashes {
  846. # The Excel ptg indices
  847. %ptg = (
  848. 'ptgExp' => 0x01,
  849. 'ptgTbl' => 0x02,
  850. 'ptgAdd' => 0x03,
  851. 'ptgSub' => 0x04,
  852. 'ptgMul' => 0x05,
  853. 'ptgDiv' => 0x06,
  854. 'ptgPower' => 0x07,
  855. 'ptgConcat' => 0x08,
  856. 'ptgLT' => 0x09,
  857. 'ptgLE' => 0x0A,
  858. 'ptgEQ' => 0x0B,
  859. 'ptgGE' => 0x0C,
  860. 'ptgGT' => 0x0D,
  861. 'ptgNE' => 0x0E,
  862. 'ptgIsect' => 0x0F,
  863. 'ptgUnion' => 0x10,
  864. 'ptgRange' => 0x11,
  865. 'ptgUplus' => 0x12,
  866. 'ptgUminus' => 0x13,
  867. 'ptgPercent' => 0x14,
  868. 'ptgParen' => 0x15,
  869. 'ptgMissArg' => 0x16,
  870. 'ptgStr' => 0x17,
  871. 'ptgAttr' => 0x19,
  872. 'ptgSheet' => 0x1A,
  873. 'ptgEndSheet' => 0x1B,
  874. 'ptgErr' => 0x1C,
  875. 'ptgBool' => 0x1D,
  876. 'ptgInt' => 0x1E,
  877. 'ptgNum' => 0x1F,
  878. 'ptgArray' => 0x20,
  879. 'ptgFunc' => 0x21,
  880. 'ptgFuncVar' => 0x22,
  881. 'ptgName' => 0x23,
  882. 'ptgRef' => 0x24,
  883. 'ptgArea' => 0x25,
  884. 'ptgMemArea' => 0x26,
  885. 'ptgMemErr' => 0x27,
  886. 'ptgMemNoMem' => 0x28,
  887. 'ptgMemFunc' => 0x29,
  888. 'ptgRefErr' => 0x2A,
  889. 'ptgAreaErr' => 0x2B,
  890. 'ptgRefN' => 0x2C,
  891. 'ptgAreaN' => 0x2D,
  892. 'ptgMemAreaN' => 0x2E,
  893. 'ptgMemNoMemN' => 0x2F,
  894. 'ptgNameX' => 0x39,
  895. 'ptgRef3d' => 0x3A,
  896. 'ptgArea3d' => 0x3B,
  897. 'ptgRefErr3d' => 0x3C,
  898. 'ptgAreaErr3d' => 0x3D,
  899. 'ptgArrayV' => 0x40,
  900. 'ptgFuncV' => 0x41,
  901. 'ptgFuncVarV' => 0x42,
  902. 'ptgNameV' => 0x43,
  903. 'ptgRefV' => 0x44,
  904. 'ptgAreaV' => 0x45,
  905. 'ptgMemAreaV' => 0x46,
  906. 'ptgMemErrV' => 0x47,
  907. 'ptgMemNoMemV' => 0x48,
  908. 'ptgMemFuncV' => 0x49,
  909. 'ptgRefErrV' => 0x4A,
  910. 'ptgAreaErrV' => 0x4B,
  911. 'ptgRefNV' => 0x4C,
  912. 'ptgAreaNV' => 0x4D,
  913. 'ptgMemAreaNV' => 0x4E,
  914. 'ptgMemNoMemN' => 0x4F,
  915. 'ptgFuncCEV' => 0x58,
  916. 'ptgNameXV' => 0x59,
  917. 'ptgRef3dV' => 0x5A,
  918. 'ptgArea3dV' => 0x5B,
  919. 'ptgRefErr3dV' => 0x5C,
  920. 'ptgAreaErr3d' => 0x5D,
  921. 'ptgArrayA' => 0x60,
  922. 'ptgFuncA' => 0x61,
  923. 'ptgFuncVarA' => 0x62,
  924. 'ptgNameA' => 0x63,
  925. 'ptgRefA' => 0x64,
  926. 'ptgAreaA' => 0x65,
  927. 'ptgMemAreaA' => 0x66,
  928. 'ptgMemErrA' => 0x67,
  929. 'ptgMemNoMemA' => 0x68,
  930. 'ptgMemFuncA' => 0x69,
  931. 'ptgRefErrA' => 0x6A,
  932. 'ptgAreaErrA' => 0x6B,
  933. 'ptgRefNA' => 0x6C,
  934. 'ptgAreaNA' => 0x6D,
  935. 'ptgMemAreaNA' => 0x6E,
  936. 'ptgMemNoMemN' => 0x6F,
  937. 'ptgFuncCEA' => 0x78,
  938. 'ptgNameXA' => 0x79,
  939. 'ptgRef3dA' => 0x7A,
  940. 'ptgArea3dA' => 0x7B,
  941. 'ptgRefErr3dA' => 0x7C,
  942. 'ptgAreaErr3d' => 0x7D,
  943. );
  944. # Thanks to Michael Meeks and Gnumeric for the initial arg values.
  945. #
  946. # The following hash was generated by "function_locale.pl" in the distro.
  947. # Refer to function_locale.pl for non-English function names.
  948. #
  949. # The array elements are as follow:
  950. # ptg: The Excel function ptg code.
  951. # args: The number of arguments that the function takes:
  952. # >=0 is a fixed number of arguments.
  953. # -1 is a variable number of arguments.
  954. # class: The reference, value or array class of the function args.
  955. # vol: The function is volatile.
  956. #
  957. %functions = (
  958. # ptg args class vol
  959. 'COUNT' => [ 0, -1, 0, 0 ],
  960. 'IF' => [ 1, -1, 1, 0 ],
  961. 'ISNA' => [ 2, 1, 1, 0 ],
  962. 'ISERROR' => [ 3, 1, 1, 0 ],
  963. 'SUM' => [ 4, -1, 0, 0 ],
  964. 'AVERAGE' => [ 5, -1, 0, 0 ],
  965. 'MIN' => [ 6, -1, 0, 0 ],
  966. 'MAX' => [ 7, -1, 0, 0 ],
  967. 'ROW' => [ 8, -1, 0, 0 ],
  968. 'COLUMN' => [ 9, -1, 0, 0 ],
  969. 'NA' => [ 10, 0, 0, 0 ],
  970. 'NPV' => [ 11, -1, 1, 0 ],
  971. 'STDEV' => [ 12, -1, 0, 0 ],
  972. 'DOLLAR' => [ 13, -1, 1, 0 ],
  973. 'FIXED' => [ 14, -1, 1, 0 ],
  974. 'SIN' => [ 15, 1, 1, 0 ],
  975. 'COS' => [ 16, 1, 1, 0 ],
  976. 'TAN' => [ 17, 1, 1, 0 ],
  977. 'ATAN' => [ 18, 1, 1, 0 ],
  978. 'PI' => [ 19, 0, 1, 0 ],
  979. 'SQRT' => [ 20, 1, 1, 0 ],
  980. 'EXP' => [ 21, 1, 1, 0 ],
  981. 'LN' => [ 22, 1, 1, 0 ],
  982. 'LOG10' => [ 23, 1, 1, 0 ],
  983. 'ABS' => [ 24, 1, 1, 0 ],
  984. 'INT' => [ 25, 1, 1, 0 ],
  985. 'SIGN' => [ 26, 1, 1, 0 ],
  986. 'ROUND' => [ 27, 2, 1, 0 ],
  987. 'LOOKUP' => [ 28, -1, 0, 0 ],
  988. 'INDEX' => [ 29, -1, 0, 1 ],
  989. 'REPT' => [ 30, 2, 1, 0 ],
  990. 'MID' => [ 31, 3, 1, 0 ],
  991. 'LEN' => [ 32, 1, 1, 0 ],
  992. 'VALUE' => [ 33, 1, 1, 0 ],
  993. 'TRUE' => [ 34, 0, 1, 0 ],
  994. 'FALSE' => [ 35, 0, 1, 0 ],
  995. 'AND' => [ 36, -1, 1, 0 ],
  996. 'OR' => [ 37, -1, 1, 0 ],
  997. 'NOT' => [ 38, 1, 1, 0 ],
  998. 'MOD' => [ 39, 2, 1, 0 ],
  999. 'DCOUNT' => [ 40, 3, 0, 0 ],
  1000. 'DSUM' => [ 41, 3, 0, 0 ],
  1001. 'DAVERAGE' => [ 42, 3, 0, 0 ],
  1002. 'DMIN' => [ 43, 3, 0, 0 ],
  1003. 'DMAX' => [ 44, 3, 0, 0 ],
  1004. 'DSTDEV' => [ 45, 3, 0, 0 ],
  1005. 'VAR' => [ 46, -1, 0, 0 ],
  1006. 'DVAR' => [ 47, 3, 0, 0 ],
  1007. 'TEXT' => [ 48, 2, 1, 0 ],
  1008. 'LINEST' => [ 49, -1, 0, 0 ],
  1009. 'TREND' => [ 50, -1, 0, 0 ],
  1010. 'LOGEST' => [ 51, -1, 0, 0 ],
  1011. 'GROWTH' => [ 52, -1, 0, 0 ],
  1012. 'PV' => [ 56, -1, 1, 0 ],
  1013. 'FV' => [ 57, -1, 1, 0 ],
  1014. 'NPER' => [ 58, -1, 1, 0 ],
  1015. 'PMT' => [ 59, -1, 1, 0 ],
  1016. 'RATE' => [ 60, -1, 1, 0 ],
  1017. 'MIRR' => [ 61, 3, 0, 0 ],
  1018. 'IRR' => [ 62, -1, 0, 0 ],
  1019. 'RAND' => [ 63, 0, 1, 1 ],
  1020. 'MATCH' => [ 64, -1, 0, 0 ],
  1021. 'DATE' => [ 65, 3, 1, 0 ],
  1022. 'TIME' => [ 66, 3, 1, 0 ],
  1023. 'DAY' => [ 67, 1, 1, 0 ],
  1024. 'MONTH' => [ 68, 1, 1, 0 ],
  1025. 'YEAR' => [ 69, 1, 1, 0 ],
  1026. 'WEEKDAY' => [ 70, -1, 1, 0 ],
  1027. 'HOUR' => [ 71, 1, 1, 0 ],
  1028. 'MINUTE' => [ 72, 1, 1, 0 ],
  1029. 'SECOND' => [ 73, 1, 1, 0 ],
  1030. 'NOW' => [ 74, 0, 1, 1 ],
  1031. 'AREAS' => [ 75, 1, 0, 1 ],
  1032. 'ROWS' => [ 76, 1, 0, 1 ],
  1033. 'COLUMNS' => [ 77, 1, 0, 1 ],
  1034. 'OFFSET' => [ 78, -1, 0, 1 ],
  1035. 'SEARCH' => [ 82, -1, 1, 0 ],
  1036. 'TRANSPOSE' => [ 83, 1, 1, 0 ],
  1037. 'TYPE' => [ 86, 1, 1, 0 ],
  1038. 'ATAN2' => [ 97, 2, 1, 0 ],
  1039. 'ASIN' => [ 98, 1, 1, 0 ],
  1040. 'ACOS' => [ 99, 1, 1, 0 ],
  1041. 'CHOOSE' => [ 100, -1, 1, 0 ],
  1042. 'HLOOKUP' => [ 101, -1, 0, 0 ],
  1043. 'VLOOKUP' => [ 102, -1, 0, 0 ],
  1044. 'ISREF' => [ 105, 1, 0, 0 ],
  1045. 'LOG' => [ 109, -1, 1, 0 ],
  1046. 'CHAR' => [ 111, 1, 1, 0 ],
  1047. 'LOWER' => [ 112, 1, 1, 0 ],
  1048. 'UPPER' => [ 113, 1, 1, 0 ],
  1049. 'PROPER' => [ 114, 1, 1, 0 ],
  1050. 'LEFT' => [ 115, -1, 1, 0 ],
  1051. 'RIGHT' => [ 116, -1, 1, 0 ],
  1052. 'EXACT' => [ 117, 2, 1, 0 ],
  1053. 'TRIM' => [ 118, 1, 1, 0 ],
  1054. 'REPLACE' => [ 119, 4, 1, 0 ],
  1055. 'SUBSTITUTE' => [ 120, -1, 1, 0 ],
  1056. 'CODE' => [ 121, 1, 1, 0 ],
  1057. 'FIND' => [ 124, -1, 1, 0 ],
  1058. 'CELL' => [ 125, -1, 0, 1 ],
  1059. 'ISERR' => [ 126, 1, 1, 0 ],
  1060. 'ISTEXT' => [ 127, 1, 1, 0 ],
  1061. 'ISNUMBER' => [ 128, 1, 1, 0 ],
  1062. 'ISBLANK' => [ 129, 1, 1, 0 ],
  1063. 'T' => [ 130, 1, 0, 0 ],
  1064. 'N' => [ 131, 1, 0, 0 ],
  1065. 'DATEVALUE' => [ 140, 1, 1, 0 ],
  1066. 'TIMEVALUE' => [ 141, 1, 1, 0 ],
  1067. 'SLN' => [ 142, 3, 1, 0 ],
  1068. 'SYD' => [ 143, 4, 1, 0 ],
  1069. 'DDB' => [ 144, -1, 1, 0 ],
  1070. 'INDIRECT' => [ 148, -1, 1, 1 ],
  1071. 'CALL' => [ 150, -1, 1, 0 ],
  1072. 'CLEAN' => [ 162, 1, 1, 0 ],
  1073. 'MDETERM' => [ 163, 1, 2, 0 ],
  1074. 'MINVERSE' => [ 164, 1, 2, 0 ],
  1075. 'MMULT' => [ 165, 2, 2, 0 ],
  1076. 'IPMT' => [ 167, -1, 1, 0 ],
  1077. 'PPMT' => [ 168, -1, 1, 0 ],
  1078. 'COUNTA' => [ 169, -1, 0, 0 ],
  1079. 'PRODUCT' => [ 183, -1, 0, 0 ],
  1080. 'FACT' => [ 184, 1, 1, 0 ],
  1081. 'DPRODUCT' => [ 189, 3, 0, 0 ],
  1082. 'ISNONTEXT' => [ 190, 1, 1, 0 ],
  1083. 'STDEVP' => [ 193, -1, 0, 0 ],
  1084. 'VARP' => [ 194, -1, 0, 0 ],
  1085. 'DSTDEVP' => [ 195, 3, 0, 0 ],
  1086. 'DVARP' => [ 196, 3, 0, 0 ],
  1087. 'TRUNC' => [ 197, -1, 1, 0 ],
  1088. 'ISLOGICAL' => [ 198, 1, 1, 0 ],
  1089. 'DCOUNTA' => [ 199, 3, 0, 0 ],
  1090. 'ROUNDUP' => [ 212, 2, 1, 0 ],
  1091. 'ROUNDDOWN' => [ 213, 2, 1, 0 ],
  1092. 'RANK' => [ 216, -1, 0, 0 ],
  1093. 'ADDRESS' => [ 219, -1, 1, 0 ],
  1094. 'DAYS360' => [ 220, -1, 1, 0 ],
  1095. 'TODAY' => [ 221, 0, 1, 1 ],
  1096. 'VDB' => [ 222, -1, 1, 0 ],
  1097. 'MEDIAN' => [ 227, -1, 0, 0 ],
  1098. 'SUMPRODUCT' => [ 228, -1, 2, 0 ],
  1099. 'SINH' => [ 229, 1, 1, 0 ],
  1100. 'COSH' => [ 230, 1, 1, 0 ],
  1101. 'TANH' => [ 231, 1, 1, 0 ],
  1102. 'ASINH' => [ 232, 1, 1, 0 ],
  1103. 'ACOSH' => [ 233, 1, 1, 0 ],
  1104. 'ATANH' => [ 234, 1, 1, 0 ],
  1105. 'DGET' => [ 235, 3, 0, 0 ],
  1106. 'INFO' => [ 244, 1, 1, 1 ],
  1107. 'DB' => [ 247, -1, 1, 0 ],
  1108. 'FREQUENCY' => [ 252, 2, 0, 0 ],
  1109. 'ERROR.TYPE' => [ 261, 1, 1, 0 ],
  1110. 'REGISTER.ID' => [ 267, -1, 1, 0 ],
  1111. 'AVEDEV' => [ 269, -1, 0, 0 ],
  1112. 'BETADIST' => [ 270, -1, 1, 0 ],
  1113. 'GAMMALN' => [ 271, 1, 1, 0 ],
  1114. 'BETAINV' => [ 272, -1, 1, 0 ],
  1115. 'BINOMDIST' => [ 273, 4, 1, 0 ],
  1116. 'CHIDIST' => [ 274, 2, 1, 0 ],
  1117. 'CHIINV' => [ 275, 2, 1, 0 ],
  1118. 'COMBIN' => [ 276, 2, 1, 0 ],
  1119. 'CONFIDENCE' => [ 277, 3, 1, 0 ],
  1120. 'CRITBINOM' => [ 278, 3, 1, 0 ],
  1121. 'EVEN' => [ 279, 1, 1, 0 ],
  1122. 'EXPONDIST' => [ 280, 3, 1, 0 ],
  1123. 'FDIST' => [ 281, 3, 1, 0 ],
  1124. 'FINV' => [ 282, 3, 1, 0 ],
  1125. 'FISHER' => [ 283, 1, 1, 0 ],
  1126. 'FISHERINV' => [ 284, 1, 1, 0 ],
  1127. 'FLOOR' => [ 285, 2, 1, 0 ],
  1128. 'GAMMADIST' => [ 286, 4, 1, 0 ],
  1129. 'GAMMAINV' => [ 287, 3, 1, 0 ],
  1130. 'CEILING' => [ 288, 2, 1, 0 ],
  1131. 'HYPGEOMDIST' => [ 289, 4, 1, 0 ],
  1132. 'LOGNORMDIST' => [ 290, 3, 1, 0 ],
  1133. 'LOGINV' => [ 291, 3, 1, 0 ],
  1134. 'NEGBINOMDIST' => [ 292, 3, 1, 0 ],
  1135. 'NORMDIST' => [ 293, 4, 1, 0 ],
  1136. 'NORMSDIST' => [ 294, 1, 1, 0 ],
  1137. 'NORMINV' => [ 295, 3, 1, 0 ],
  1138. 'NORMSINV' => [ 296, 1, 1, 0 ],
  1139. 'STANDARDIZE' => [ 297, 3, 1, 0 ],
  1140. 'ODD' => [ 298, 1, 1, 0 ],
  1141. 'PERMUT' => [ 299, 2, 1, 0 ],
  1142. 'POISSON' => [ 300, 3, 1, 0 ],
  1143. 'TDIST' => [ 301, 3, 1, 0 ],
  1144. 'WEIBULL' => [ 302, 4, 1, 0 ],
  1145. 'SUMXMY2' => [ 303, 2, 2, 0 ],
  1146. 'SUMX2MY2' => [ 304, 2, 2, 0 ],
  1147. 'SUMX2PY2' => [ 305, 2, 2, 0 ],
  1148. 'CHITEST' => [ 306, 2, 2, 0 ],
  1149. 'CORREL' => [ 307, 2, 2, 0 ],
  1150. 'COVAR' => [ 308, 2, 2, 0 ],
  1151. 'FORECAST' => [ 309, 3, 2, 0 ],
  1152. 'FTEST' => [ 310, 2, 2, 0 ],
  1153. 'INTERCEPT' => [ 311, 2, 2, 0 ],
  1154. 'PEARSON' => [ 312, 2, 2, 0 ],
  1155. 'RSQ' => [ 313, 2, 2, 0 ],
  1156. 'STEYX' => [ 314, 2, 2, 0 ],
  1157. 'SLOPE' => [ 315, 2, 2, 0 ],
  1158. 'TTEST' => [ 316, 4, 2, 0 ],
  1159. 'PROB' => [ 317, -1, 2, 0 ],
  1160. 'DEVSQ' => [ 318, -1, 0, 0 ],
  1161. 'GEOMEAN' => [ 319, -1, 0, 0 ],
  1162. 'HARMEAN' => [ 320, -1, 0, 0 ],
  1163. 'SUMSQ' => [ 321, -1, 0, 0 ],
  1164. 'KURT' => [ 322, -1, 0, 0 ],
  1165. 'SKEW' => [ 323, -1, 0, 0 ],
  1166. 'ZTEST' => [ 324, -1, 0, 0 ],
  1167. 'LARGE' => [ 325, 2, 0, 0 ],
  1168. 'SMALL' => [ 326, 2, 0, 0 ],
  1169. 'QUARTILE' => [ 327, 2, 0, 0 ],
  1170. 'PERCENTILE' => [ 328, 2, 0, 0 ],
  1171. 'PERCENTRANK' => [ 329, -1, 0, 0 ],
  1172. 'MODE' => [ 330, -1, 2, 0 ],
  1173. 'TRIMMEAN' => [ 331, 2, 0, 0 ],
  1174. 'TINV' => [ 332, 2, 1, 0 ],
  1175. 'CONCATENATE' => [ 336, -1, 1, 0 ],
  1176. 'POWER' => [ 337, 2, 1, 0 ],
  1177. 'RADIANS' => [ 342, 1, 1, 0 ],
  1178. 'DEGREES' => [ 343, 1, 1, 0 ],
  1179. 'SUBTOTAL' => [ 344, -1, 0, 0 ],
  1180. 'SUMIF' => [ 345, -1, 0, 0 ],
  1181. 'COUNTIF' => [ 346, 2, 0, 0 ],
  1182. 'COUNTBLANK' => [ 347, 1, 0, 0 ],
  1183. 'ROMAN' => [ 354, -1, 1, 0 ],
  1184. );
  1185. }
  1186. 1;
  1187. __END__
  1188. =head1 NAME
  1189. Formula - A class for generating Excel formulas
  1190. =head1 SYNOPSIS
  1191. See the documentation for Spreadsheet::WriteExcel
  1192. =head1 DESCRIPTION
  1193. This module is used by Spreadsheet::WriteExcel. You do not need to use it directly.
  1194. =head1 NOTES
  1195. The following notes are to help developers and maintainers understand the sequence of operation. They are also intended as a pro-memoria for the author. ;-)
  1196. Spreadsheet::WriteExcel::Formula converts a textual representation of a formula into the pre-parsed binary format that Excel uses to store formulas. For example C<1+2*3> is stored as follows: C<1E 01 00 1E 02 00 1E 03 00 05 03>.
  1197. This string is comprised of operators and operands arranged in a reverse-Polish format. The meaning of the tokens in the above example is shown in the following table:
  1198. Token Name Value
  1199. 1E ptgInt 0001 (stored as 01 00)
  1200. 1E ptgInt 0002 (stored as 02 00)
  1201. 1E ptgInt 0003 (stored as 03 00)
  1202. 05 ptgMul
  1203. 03 ptgAdd
  1204. The tokens and token names are defined in the "Excel Developer's Kit" from Microsoft Press. C<ptg> stands for Parse ThinG (as in "That lexer can't grok it, it's a parse thang.")
  1205. In general the tokens fall into two categories: operators such as C<ptgMul> and operands such as C<ptgInt>. When the formula is evaluated by Excel the operand tokens push values onto a stack. The operator tokens then pop the required number of operands off of the stack, perform an operation and push the resulting value back onto the stack. This methodology is similar to the basic operation of a reverse-Polish (RPN) calculator.
  1206. Spreadsheet::WriteExcel::Formula parses a formula using a C<Parse::RecDescent> parser (at a later stage it may use a C<Parse::Yapp> parser or C<Parse::FastDescent>).
  1207. The parser converts the textual representation of a formula into a parse tree. Thus, C<1+2*3> is converted into something like the following, C<e> stands for expression:
  1208. e
  1209. / | \
  1210. 1 + e
  1211. / | \
  1212. 2 * 3
  1213. The function C<_reverse_tree()> recurses down through this structure swapping the order of operators followed by operands to produce a reverse-Polish tree. In other words the formula is converted from in-fix notation to post-fix. Following the above example the resulting tree would look like this:
  1214. e
  1215. / | \
  1216. 1 e +
  1217. / | \
  1218. 2 3 *
  1219. The result of the recursion is a single array of tokens. In our example the simplified form would look like the following:
  1220. (1, 2, 3, *, +)
  1221. The actual return value contains some additional information to help in the secondary parsing stage:
  1222. (_num, 1, _num, 2, _num, 3, ptgMul, ptgAdd, _arg, 1)
  1223. The additional tokens are:
  1224. Token Meaning
  1225. _num The next token is a number
  1226. _str The next token is a string
  1227. _ref2d The next token is a 2d cell reference
  1228. _ref3d The next token is a 3d cell reference
  1229. _range2d The next token is a 2d range
  1230. _range3d The next token is a 3d range
  1231. _func The next token is a function
  1232. _arg The next token is the number of args for a function
  1233. _class The next token is a function name
  1234. _vol The formula contains a voltile function
  1235. The C<_arg> token is generated for all lists but is only used for functions that take a variable number of arguments.
  1236. The C<_class> token indicates the start of the arguments to a function. This allows the post-processor to decide the "class" of the ref and range arguments that the function takes. The class can be reference, value or array. Since function calls can be nested, the class variable is stored on a stack in the C<@class> array. The class of the ref or range is then read as the top element of the stack C<$class[-1]>. When a C<_func> is read it pops the class value.
  1237. Certain Excel functions such as RAND() and NOW() are designated as volatile and must be recalculated by Excel every time that a cell is updated. Any formulas that contain one of these functions has a specially formatted C<ptgAttr> tag prepended to it to indicate that it is volatile.
  1238. A secondary parsing stage is carried out by C<parse_tokens()> which converts these tokens into a binary string. For the C<1+2*3> example this would give:
  1239. 1E 01 00 1E 02 00 1E 03 00 05 03
  1240. This two-pass method could probably have been reduced to a single pass through the C<Parse::RecDescent> parser. However, it was easier to develop and debug this way.
  1241. The token values and formula values are stored in the C<%ptg> and C<%functions> hashes. These hashes and the parser object C<$parser> are exposed as global data. This breaks the OO encapsulation, but means that they can be shared by several instances of Spreadsheet::WriteExcel called from the same program.
  1242. Non-English function names can be added to the C<%functions> hash using the C<function_locale.pl> program in the C<examples> directory of the distro. The supported languages are: German, French, Spanish, Portuguese, Dutch, Finnish, Italian and Swedish. These languages are not added by default because there are conflicts between functions names in different languages.
  1243. The parser is initialised by C<_init_parser()>. The initialisation is delayed until the first formula is parsed. This eliminates the overhead of generating the parser in programs that are not processing formulas. (The parser should really be pre-compiled, this is to-do when the grammar stabilises).
  1244. =head1 AUTHOR
  1245. John McNamara jmcnamara@cpan.org
  1246. =head1 COPYRIGHT
  1247. © MM-MMX, John McNamara.
  1248. All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.