📄 parser.php
字号:
} elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_GE) { $this->_advance(); $result2 = $this->_expression(); if (PEAR::isError($result2)) { return $result2; } $result = $this->_createTree('ptgGE', $result, $result2); } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_EQ) { $this->_advance(); $result2 = $this->_expression(); if (PEAR::isError($result2)) { return $result2; } $result = $this->_createTree('ptgEQ', $result, $result2); } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_NE) { $this->_advance(); $result2 = $this->_expression(); if (PEAR::isError($result2)) { return $result2; } $result = $this->_createTree('ptgNE', $result, $result2); } return $result; } /** * It parses a expression. It assumes the following rule: * Expr -> Term [("+" | "-") Term] * -> "string" * -> "-" Term * * @access private * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure */ function _expression() { // If it's a string return a string node if (ereg("^\"[^\"]{0,255}\"$", $this->_current_token)) { $result = $this->_createTree($this->_current_token, '', ''); $this->_advance(); return $result; } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_SUB) { // catch "-" Term $this->_advance(); $result2 = $this->_expression(); $result = $this->_createTree('ptgUminus', $result2, ''); return $result; } $result = $this->_term(); if (PEAR::isError($result)) { return $result; } while (($this->_current_token == SPREADSHEET_EXCEL_WRITER_ADD) or ($this->_current_token == SPREADSHEET_EXCEL_WRITER_SUB)) { /**/ if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_ADD) { $this->_advance(); $result2 = $this->_term(); if (PEAR::isError($result2)) { return $result2; } $result = $this->_createTree('ptgAdd', $result, $result2); } else { $this->_advance(); $result2 = $this->_term(); if (PEAR::isError($result2)) { return $result2; } $result = $this->_createTree('ptgSub', $result, $result2); } } return $result; } /** * This function just introduces a ptgParen element in the tree, so that Excel * doesn't get confused when working with a parenthesized formula afterwards. * * @access private * @see _fact() * @return array The parsed ptg'd tree */ function _parenthesizedExpression() { $result = $this->_createTree('ptgParen', $this->_expression(), ''); return $result; } /** * It parses a term. It assumes the following rule: * Term -> Fact [("*" | "/") Fact] * * @access private * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure */ function _term() { $result = $this->_fact(); if (PEAR::isError($result)) { return $result; } while (($this->_current_token == SPREADSHEET_EXCEL_WRITER_MUL) or ($this->_current_token == SPREADSHEET_EXCEL_WRITER_DIV)) { /**/ if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_MUL) { $this->_advance(); $result2 = $this->_fact(); if (PEAR::isError($result2)) { return $result2; } $result = $this->_createTree('ptgMul', $result, $result2); } else { $this->_advance(); $result2 = $this->_fact(); if (PEAR::isError($result2)) { return $result2; } $result = $this->_createTree('ptgDiv', $result, $result2); } } return $result; } /** * It parses a factor. It assumes the following rule: * Fact -> ( Expr ) * | CellRef * | CellRange * | Number * | Function * * @access private * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure */ function _fact() { if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_OPEN) { $this->_advance(); // eat the "(" $result = $this->_parenthesizedExpression(); if ($this->_current_token != SPREADSHEET_EXCEL_WRITER_CLOSE) { return $this->raiseError("')' token expected."); } $this->_advance(); // eat the ")" return $result; } // if it's a reference if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?[0-9]+$/',$this->_current_token)) { $result = $this->_createTree($this->_current_token, '', ''); $this->_advance(); return $result; } // If it's an external reference (Sheet1!A1 or Sheet1:Sheet2!A1) elseif (preg_match("/^\w+(\:\w+)?\![A-Ia-i]?[A-Za-z][0-9]+$/u",$this->_current_token)) { $result = $this->_createTree($this->_current_token, '', ''); $this->_advance(); return $result; } // If it's an external reference ('Sheet1'!A1 or 'Sheet1:Sheet2'!A1) elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\![A-Ia-i]?[A-Za-z][0-9]+$/u",$this->_current_token)) { $result = $this->_createTree($this->_current_token, '', ''); $this->_advance(); return $result; } // if it's a range elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+:(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$this->_current_token) or preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$this->_current_token)) { $result = $this->_current_token; $this->_advance(); return $result; } // If it's an external range (Sheet1!A1 or Sheet1!A1:B2) elseif (preg_match("/^\w+(\:\w+)?\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$this->_current_token)) { $result = $this->_current_token; $this->_advance(); return $result; } // If it's an external range ('Sheet1'!A1 or 'Sheet1'!A1:B2) elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/u",$this->_current_token)) { $result = $this->_current_token; $this->_advance(); return $result; } elseif (is_numeric($this->_current_token)) { $result = $this->_createTree($this->_current_token, '', ''); $this->_advance(); return $result; } // if it's a function call elseif (eregi("^[A-Z0-9\xc0-\xdc\.]+$",$this->_current_token)) { $result = $this->_func(); return $result; } return $this->raiseError("Syntax error: ".$this->_current_token. ", lookahead: ".$this->_lookahead. ", current char: ".$this->_current_char); } /** * It parses a function call. It assumes the following rule: * Func -> ( Expr [,Expr]* ) * * @access private * @return mixed The parsed ptg'd tree on success, PEAR_Error on failure */ function _func() { $num_args = 0; // number of arguments received $function = strtoupper($this->_current_token); $result = ''; // initialize result $this->_advance(); $this->_advance(); // eat the "(" while ($this->_current_token != ')') { /**/ if ($num_args > 0) { if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_COMA or $this->_current_token == SPREADSHEET_EXCEL_WRITER_SEMICOLON) { $this->_advance(); // eat the "," or ";" } else { return $this->raiseError("Syntax error: comma expected in ". "function $function, arg #{$num_args}"); } $result2 = $this->_condition(); if (PEAR::isError($result2)) { return $result2; } $result = $this->_createTree('arg', $result, $result2); } else { // first argument $result2 = $this->_condition(); if (PEAR::isError($result2)) { return $result2; } $result = $this->_createTree('arg', '', $result2); } $num_args++; } if (!isset($this->_functions[$function])) { return $this->raiseError("Function $function() doesn't exist"); } $args = $this->_functions[$function][1]; // If fixed number of args eg. TIME($i,$j,$k). Check that the number of args is valid. if (($args >= 0) and ($args != $num_args)) { return $this->raiseError("Incorrect number of arguments in function $function() "); } $result = $this->_createTree($function, $result, $num_args); $this->_advance(); // eat the ")" return $result; } /** * Creates a tree. In fact an array which may have one or two arrays (sub-trees) * as elements. * * @access private * @param mixed $value The value of this node. * @param mixed $left The left array (sub-tree) or a final node. * @param mixed $right The right array (sub-tree) or a final node. * @return array A tree */ function _createTree($value, $left, $right) { return array('value' => $value, 'left' => $left, 'right' => $right); } /** * Builds a string containing the tree in reverse polish notation (What you * would use in a HP calculator stack). * The following tree: * * + * / \ * 2 3 * * produces: "23+" * * The following tree: * * + * / \ * 3 * * / \ * 6 A1 * * produces: "36A1*+" * * In fact all operands, functions, references, etc... are written as ptg's * * @access public * @param array $tree The optional tree to convert. * @return string The tree in reverse polish notation */ function toReversePolish($tree = array()) { $polish = ""; // the string we are going to return if (empty($tree)) { // If it's the first call use _parse_tree $tree = $this->_parse_tree; } if (is_array($tree['left'])) { $converted_tree = $this->toReversePolish($tree['left']); if (PEAR::isError($converted_tree)) { return $converted_tree; } $polish .= $converted_tree; } elseif ($tree['left'] != '') { // It's a final node $converted_tree = $this->_convert($tree['left']); if (PEAR::isError($converted_tree)) { return $converted_tree; } $polish .= $converted_tree; } if (is_array($tree['right'])) { $converted_tree = $this->toReversePolish($tree['right']); if (PEAR::isError($converted_tree)) { return $converted_tree; } $polish .= $converted_tree; } elseif ($tree['right'] != '') { // It's a final node $converted_tree = $this->_convert($tree['right']); i
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -