You are here

function _locale_import_parse_arithmetic in Drupal 4

Same name and namespace in other branches
  1. 5 includes/locale.inc \_locale_import_parse_arithmetic()
  2. 6 includes/locale.inc \_locale_import_parse_arithmetic()
  3. 7 includes/locale.inc \_locale_import_parse_arithmetic()

Parses and sanitizes an arithmetic formula into a PHP expression

While parsing, we ensure, that the operators have the right precedence and associativity.

@author Jacobo Tarrio

Parameters

$string A string containing the arithmetic formula:

Return value

The PHP version of the formula

1 call to _locale_import_parse_arithmetic()
_locale_import_parse_plural_forms in includes/locale.inc
Parses a Plural-Forms entry from a Gettext Portable Object file header

File

includes/locale.inc, line 817
Admin-related functions for locale.module.

Code

function _locale_import_parse_arithmetic($string) {

  // Operator precedence table
  $prec = array(
    "(" => -1,
    ")" => -1,
    "?" => 1,
    ":" => 1,
    "||" => 3,
    "&&" => 4,
    "==" => 5,
    "!=" => 5,
    "<" => 6,
    ">" => 6,
    "<=" => 6,
    ">=" => 6,
    "+" => 7,
    "-" => 7,
    "*" => 8,
    "/" => 8,
    "%" => 8,
  );

  // Right associativity
  $rasc = array(
    "?" => 1,
    ":" => 1,
  );
  $tokens = _locale_import_tokenize_formula($string);

  // Parse by converting into infix notation then back into postfix
  $opstk = array();
  $elstk = array();
  foreach ($tokens as $token) {
    $ctok = $token;

    // Numbers and the $n variable are simply pushed into $elarr
    if (is_numeric($token)) {
      $elstk[] = $ctok;
    }
    elseif ($ctok == "n") {
      $elstk[] = '$n';
    }
    elseif ($ctok == "(") {
      $opstk[] = $ctok;
    }
    elseif ($ctok == ")") {
      $topop = array_pop($opstk);
      while ($topop != NULL && $topop != "(") {
        $elstk[] = $topop;
        $topop = array_pop($opstk);
      }
    }
    elseif ($prec[$ctok]) {

      // If it's an operator, then pop from $oparr into $elarr until the
      // precedence in $oparr is less than current, then push into $oparr
      $topop = array_pop($opstk);
      while ($topop != NULL && $prec[$topop] >= $prec[$ctok] && !($prec[$topop] == $prec[$ctok] && $rasc[$topop] && $rasc[$ctok])) {
        $elstk[] = $topop;
        $topop = array_pop($opstk);
      }
      if ($topop) {
        $opstk[] = $topop;

        // Return element to top
      }
      $opstk[] = $ctok;

      // Parentheses are not needed
    }
    else {
      return false;
    }
  }

  // Flush operator stack
  $topop = array_pop($opstk);
  while ($topop != NULL) {
    $elstk[] = $topop;
    $topop = array_pop($opstk);
  }

  // Now extract formula from stack
  $prevsize = count($elstk) + 1;
  while (count($elstk) < $prevsize) {
    $prevsize = count($elstk);
    for ($i = 2; $i < count($elstk); $i++) {
      $op = $elstk[$i];
      if ($prec[$op]) {
        $f = "";
        if ($op == ":") {
          $f = $elstk[$i - 2] . "):" . $elstk[$i - 1] . ")";
        }
        elseif ($op == "?") {
          $f = "(" . $elstk[$i - 2] . "?(" . $elstk[$i - 1];
        }
        else {
          $f = "(" . $elstk[$i - 2] . $op . $elstk[$i - 1] . ")";
        }
        array_splice($elstk, $i - 2, 3, $f);
        break;
      }
    }
  }

  // If only one element is left, the number of operators is appropriate
  if (count($elstk) == 1) {
    return $elstk[0];
  }
  else {
    return FALSE;
  }
}