• Модуль: bizproc
  • Путь к файлу: ~/bitrix/modules/bizproc/lib/Calc/Parser.php
  • Класс: BitrixBizprocCalcParser
  • Вызов: Parser::getPolishNotation
private function getPolishNotation($text)
{
	$text = trim($text);
	if (mb_strpos($text, '=') === 0)
	{
		$text = mb_substr($text, 1);
	}
	if (mb_strpos($text, '{{=') === 0 && mb_substr($text, -2) === '}}')
	{
		$text = mb_substr($text, 3);
		$text = mb_substr($text, 0, -2);
	}

	if (!$text)
	{
		$this->setError(1);

		return false;
	}

	$notation = [];
	$stack = [];
	$prev = '';

	$isFunctionArgs = function ($stack)
	{
		return (
			isset($stack[0], $stack[1], $this->functions[$stack[1][0]]) && $stack[0][0] === '('
		);
	};

	$preg = '/
		s*(s*                          |
		s*)s*                          |
		s*,s*                           | # Combine ranges of variables
		s*;s*                           | # Combine ranges of variables
		s*=s*                           |
		s*<=s*                          |
		s*>=s*                          |
		s*<>s*                          |
		s*s*                           |
		s*&s*                           | # String concatenation
		s*+s*                          | # Addition or unary plus
		s*-s*                           |
		s**s*                          |
		s*/s*                          |
		s*^s*                          | # Exponentiation
		s*%s*                           | # Percent
		s*[d.]+s*                     | # Numbers
		s*'[^']*'s*                  | # String constants in apostrophes
		s*"[^"]*"s*                     | # String constants in quotes
		(s*w+s*(s*)                  | # Function names
		s*' . CBPActivity::ValueInternalPattern . 's*  | # Variables
		(?.+)                                # Any erroneous substring
		/xi';

	while (preg_match($preg, $text, $match))
	{
		if (isset($match['error']))
		{
			$this->setError(2, $match['error']);

			return false;
		}

		$str = trim($match[0]);
		if ($str === ",")
		{
			$str = ";";
		}

		if (isset($match[1]) && $match[1])
		{
			$str = mb_strtolower($str);
			[$name] = explode('(', $str);
			$name = trim($name);
			if (isset($this->functions[$name]))
			{
				if ($stack)
				{
					while ($this->priority['f'] <= $stack[0][1])
					{
						$op = array_shift($stack);
						$notation[] = [$op[0], self::Operation];
						if (!$stack)
						{
							break;
						}
					}
				}
				array_unshift($stack, [$name, $this->priority['f']]);
			}
			else
			{
				$this->setError(3, $name);

				return false;
			}
			$str = '(';
		}

		if ($str === '-' || $str === '+')
		{
			if (
				$prev === ''
				|| in_array($prev, ['(', ';', '=', '<=', '>=', '<>', '<', '>', '&', '+', '-', '*', '/', '^'])
			)
			{
				$str .= 'm';
			}
		}

		switch ($str)
		{
			case '(':
				array_unshift($stack, ['(', $this->priority['(']]);
				array_unshift($stack, ['@', $this->priority['@']]);
				break;
			case ')':
				$hasComma = false;
				$hasArguments = $prev !== '(';
				//trailing comma
				if ($prev === ';')
				{
					array_shift($stack);
				}

				while ($op = array_shift($stack))
				{
					if ($op[0] === '(')
					{
						break;
					}
					if ($op[0] === ';')
					{
						$hasComma = true;
					}

					$isInFunction = $isFunctionArgs($stack);

					if (
						$op[0] === '@'
						&& (
							(!$hasComma && !$isInFunction)
							|| (!$hasArguments && $isInFunction)
						)
					)
					{
						continue;
					}
					$notation[] = [$op[0], self::Operation];
				}
				if ($op === null)
				{
					$this->setError(4);

					return false;
				}
				break;
			case ';' :
			case '=' :
			case '<=':
			case '>=':
			case '<>':
			case '<' :
			case '>' :
			case '&' :
			case '+' :
			case '-' :
			case '+m':
			case '-m':
			case '*' :
			case '/' :
			case '^' :
			case '%' :
				if (!$stack)
				{
					array_unshift($stack, [$str, $this->priority[$str]]);
					if ($str === ';')
					{
						$notation[] = ['@', self::Operation];
					}
					break;
				}
				while ($this->priority[$str] <= $stack[0][1])
				{
					$op = array_shift($stack);
					$notation[] = [$op[0], self::Operation];
					if (!$stack)
					{
						break;
					}
				}
				array_unshift($stack, [$str, $this->priority[$str]]);
				break;
			default:
				if (mb_strpos($str, '0') === 0 || (int)$str)
				{
					$notation[] = [(float)$str, self::Constant];
					break;
				}
				if (mb_strpos($str, '"') === 0 || mb_strpos($str, "'") === 0)
				{
					$notation[] = [mb_substr($str, 1, -1), self::Constant];
					break;
				}
				$notation[] = [$str, self::Variable];
		}
		$text = mb_substr($text, mb_strlen($match[0]));
		$prev = $str;
	}
	while ($op = array_shift($stack))
	{
		if ($op[0] === '(')
		{
			$this->setError(5);

			return false;
		}
		$notation[] = [$op[0], self::Operation];
	}

	return $notation;
}