Source of file Parser.php
Size: 9,545 Bytes - Last Modified: 2014-03-12T23:21:18+01:00
/home/theseer/Downloads/ZendFramework-2.3.0/library/Zend/I18n/Translator/Plural/Parser.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 | <?php /** * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ namespace Zend\I18n\Translator\Plural; use Zend\I18n\Exception; /** * Plural rule parser. * * This plural rule parser is implemented after the article "Top Down Operator * Precedence" described in <http://javascript.crockford.com/tdop/tdop.html>. */ class Parser { /** * String to parse. * * @var string */ protected $string; /** * Current lexer position in the string. * * @var int */ protected $currentPos; /** * Current token. * * @var Symbol */ protected $currentToken; /** * Table of symbols. * * @var array */ protected $symbolTable = array(); /** * Create a new plural parser. * */ public function __construct() { $this->populateSymbolTable(); } /** * Populate the symbol table. * * @return void */ protected function populateSymbolTable() { // Ternary operators $this->registerSymbol('?', 20)->setLeftDenotationGetter( function (Symbol $self, Symbol $left) { $self->first = $left; $self->second = $self->parser->expression(); $self->parser->advance(':'); $self->third = $self->parser->expression(); return $self; } ); $this->registerSymbol(':'); // Boolean operators $this->registerLeftInfixSymbol('||', 30); $this->registerLeftInfixSymbol('&&', 40); // Equal operators $this->registerLeftInfixSymbol('==', 50); $this->registerLeftInfixSymbol('!=', 50); // Compare operators $this->registerLeftInfixSymbol('>', 50); $this->registerLeftInfixSymbol('<', 50); $this->registerLeftInfixSymbol('>=', 50); $this->registerLeftInfixSymbol('<=', 50); // Add operators $this->registerLeftInfixSymbol('-', 60); $this->registerLeftInfixSymbol('+', 60); // Multiply operators $this->registerLeftInfixSymbol('*', 70); $this->registerLeftInfixSymbol('/', 70); $this->registerLeftInfixSymbol('%', 70); // Not operator $this->registerPrefixSymbol('!', 80); // Literals $this->registerSymbol('n')->setNullDenotationGetter( function (Symbol $self) { return $self; } ); $this->registerSymbol('number')->setNullDenotationGetter( function (Symbol $self) { return $self; } ); // Parentheses $this->registerSymbol('(')->setNullDenotationGetter( function (Symbol $self) { $expression = $self->parser->expression(); $self->parser->advance(')'); return $expression; } ); $this->registerSymbol(')'); // Eof $this->registerSymbol('eof'); } /** * Register a left infix symbol. * * @param string $id * @param int $leftBindingPower * @return void */ protected function registerLeftInfixSymbol($id, $leftBindingPower) { $this->registerSymbol($id, $leftBindingPower)->setLeftDenotationGetter( function (Symbol $self, Symbol $left) use ($leftBindingPower) { $self->first = $left; $self->second = $self->parser->expression($leftBindingPower); return $self; } ); } /** * Register a right infix symbol. * * @param string $id * @param int $leftBindingPower * @return void */ protected function registerRightInfixSymbol($id, $leftBindingPower) { $this->registerSymbol($id, $leftBindingPower)->setLeftDenotationGetter( function (Symbol $self, Symbol $left) use ($leftBindingPower) { $self->first = $left; $self->second = $self->parser->expression($leftBindingPower - 1); return $self; } ); } /** * Register a prefix symbol. * * @param string $id * @param int $leftBindingPower * @return void */ protected function registerPrefixSymbol($id, $leftBindingPower) { $this->registerSymbol($id, $leftBindingPower)->setNullDenotationGetter( function (Symbol $self) use ($leftBindingPower) { $self->first = $self->parser->expression($leftBindingPower); $self->second = null; return $self; } ); } /** * Register a symbol. * * @param string $id * @param int $leftBindingPower * @return Symbol */ protected function registerSymbol($id, $leftBindingPower = 0) { if (isset($this->symbolTable[$id])) { $symbol = $this->symbolTable[$id]; $symbol->leftBindingPower = max( $symbol->leftBindingPower, $leftBindingPower ); } else { $symbol = new Symbol($this, $id, $leftBindingPower); $this->symbolTable[$id] = $symbol; } return $symbol; } /** * Get a new symbol. * * @param string $id */ protected function getSymbol($id) { if (!isset($this->symbolTable[$id])) { // Unkown symbol exception } return clone $this->symbolTable[$id]; } /** * Parse a string. * * @param string $string * @return array */ public function parse($string) { $this->string = $string . "\0"; $this->currentPos = 0; $this->currentToken = $this->getNextToken(); return $this->expression(); } /** * Parse an expression. * * @param int $rightBindingPower * @return Symbol */ public function expression($rightBindingPower = 0) { $token = $this->currentToken; $this->currentToken = $this->getNextToken(); $left = $token->getNullDenotation(); while ($rightBindingPower < $this->currentToken->leftBindingPower) { $token = $this->currentToken; $this->currentToken = $this->getNextToken(); $left = $token->getLeftDenotation($left); } return $left; } /** * Advance the current token and optionally check the old token id. * * @param string $id * @return void * @throws Exception\ParseException */ public function advance($id = null) { if ($id !== null && $this->currentToken->id !== $id) { throw new Exception\ParseException(sprintf( 'Expected token with id %s but received %s', $id, $this->currentToken->id )); } $this->currentToken = $this->getNextToken(); } /** * Get the next token. * * @return array * @throws Exception\ParseException */ protected function getNextToken() { while ($this->string[$this->currentPos] === ' ' || $this->string[$this->currentPos] === "\t") { $this->currentPos++; } $result = $this->string[$this->currentPos++]; $value = null; switch ($result) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': while (ctype_digit($this->string[$this->currentPos])) { $result .= $this->string[$this->currentPos++]; } $id = 'number'; $value = (int) $result; break; case '=': case '&': case '|': if ($this->string[$this->currentPos] === $result) { $this->currentPos++; $id = $result . $result; } else { // Yield error } break; case '!': case '<': case '>': if ($this->string[$this->currentPos] === '=') { $this->currentPos++; $result .= '='; } $id = $result; break; case '*': case '/': case '%': case '+': case '-': case 'n': case '?': case ':': case '(': case ')': $id = $result; break; case ';': case "\n": case "\0": $id = 'eof'; $this->currentPos--; break; default: throw new Exception\ParseException(sprintf( 'Found invalid character "%s" in input stream', $result )); break; } $token = $this->getSymbol($id); $token->value = $value; return $token; } } |