[ Index ]

PHP Cross Reference of vtigercrm-6.1.0

title

Body

[close]

/pkg/vtiger/extensions/Webservices/third-party/LexerGenerator/ -> Parser.y (source)

   1  %name PHP_LexerGenerator_Parser
   2  %declare_class {class PHP_LexerGenerator_Parser}
   3  %include {
   4  /* ?><?php {//*/

   5  /**

   6   * PHP_LexerGenerator, a php 5 lexer generator.

   7   * 

   8   * This lexer generator translates a file in a format similar to

   9   * re2c ({@link http://re2c.org}) and translates it into a PHP 5-based lexer

  10   *

  11   * PHP version 5

  12   *

  13   * LICENSE:

  14   * 

  15   * Copyright (c) 2006, Gregory Beaver <[email protected]>

  16   * All rights reserved.

  17   *

  18   * Redistribution and use in source and binary forms, with or without

  19   * modification, are permitted provided that the following conditions

  20   * are met:

  21   *

  22   *     * Redistributions of source code must retain the above copyright

  23   *       notice, this list of conditions and the following disclaimer.

  24   *     * Redistributions in binary form must reproduce the above copyright

  25   *       notice, this list of conditions and the following disclaimer in

  26   *       the documentation and/or other materials provided with the distribution.

  27   *     * Neither the name of the PHP_LexerGenerator nor the names of its

  28   *       contributors may be used to endorse or promote products derived

  29   *       from this software without specific prior written permission.

  30   *

  31   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS

  32   * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,

  33   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR

  34   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR

  35   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

  36   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,

  37   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR

  38   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY

  39   * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING

  40   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS

  41   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

  42   *

  43   * @category   php

  44   * @package    PHP_LexerGenerator

  45   * @author     Gregory Beaver <[email protected]>

  46   * @copyright  2006 Gregory Beaver

  47   * @license    http://www.opensource.org/licenses/bsd-license.php New BSD License

  48   * @version    CVS: $Id$

  49   * @since      File available since Release 0.1.0

  50   */
  51  /**

  52   * For regular expression validation

  53   */
  54  require_once 'PHP/LexerGenerator/Regex/Lexer.php';
  55  require_once 'PHP/LexerGenerator/Regex/Parser.php';
  56  require_once 'PHP/LexerGenerator/Exception.php';
  57  /**

  58   * Token parser for plex files.

  59   * 

  60   * This parser converts tokens pulled from {@link PHP_LexerGenerator_Lexer}

  61   * into abstract patterns and rules, then creates the output file

  62   * @package    PHP_LexerGenerator

  63   * @author     Gregory Beaver <[email protected]>

  64   * @copyright  2006 Gregory Beaver

  65   * @license    http://www.php.net/license/3_01.txt  PHP License 3.01

  66   * @version    0.2.0

  67   * @since      Class available since Release 0.1.0

  68   */
  69  }
  70  %syntax_error {
  71      echo "Syntax Error on line " . $this->lex->line . ": token '" . 
  72          $this->lex->value . "' while parsing rule:";
  73      foreach ($this->yystack as $entry) {
  74          echo $this->tokenName($entry->major) . ' ';
  75      }
  76      foreach ($this->yy_get_expected_tokens($yymajor) as $token) {
  77          $expect[] = self::$yyTokenName[$token];
  78      }
  79      throw new Exception('Unexpected ' . $this->tokenName($yymajor) . '(' . $TOKEN
  80          . '), expected one of: ' . implode(',', $expect));
  81  }
  82  %include_class {
  83      private $patterns;
  84      private $out;
  85      private $lex;
  86      private $input;
  87      private $counter;
  88      private $token;
  89      private $value;
  90      private $line;
  91      private $_regexLexer;
  92      private $_regexParser;
  93  
  94      public $transTable = array(
  95          1 => self::PHPCODE,
  96          2 => self::COMMENTSTART,
  97          3 => self::COMMENTEND,
  98          4 => self::QUOTE,
  99          5 => self::PATTERN,
 100          6 => self::CODE,
 101          7 => self::SUBPATTERN,
 102          8 => self::PI,
 103      );
 104  
 105      function __construct($outfile, $lex)
 106      {
 107          $this->out = fopen($outfile, 'wb');
 108          if (!$this->out) {
 109              throw new Exception('unable to open lexer output file "' . $outfile . '"');
 110          }
 111          $this->lex = $lex;
 112          $this->_regexLexer = new PHP_LexerGenerator_Regex_Lexer('');
 113          $this->_regexParser = new PHP_LexerGenerator_Regex_Parser($this->_regexLexer);
 114      }
 115  
 116      function outputRules($rules, $statename)
 117      {
 118          static $ruleindex = 1;
 119          $patterns = array();
 120          $pattern = '/';
 121          $ruleMap = array();
 122          $tokenindex = array();
 123          $i = 0;
 124          $actualindex = 1;
 125          foreach ($rules as $rule) {
 126              $ruleMap[$i++] = $actualindex;
 127              $tokenindex[$actualindex] = $rule['subpatterns'];
 128              $actualindex += $rule['subpatterns'] + 1;
 129              $patterns[] = '^(' . $rule['pattern'] . ')';
 130          }
 131          $tokenindex = var_export($tokenindex, true);
 132          $tokenindex = explode("\n", $tokenindex);
 133          // indent for prettiness

 134          $tokenindex = implode("\n            ", $tokenindex);
 135          $pattern .= implode('|', $patterns);
 136          $pattern .= '/';
 137          if (!$statename) {
 138              $statename = $ruleindex;
 139          }
 140          fwrite($this->out, '
 141      function yylex' . $ruleindex . '()
 142      {
 143          $tokenMap = ' . $tokenindex . ';
 144          if (' . $this->counter . ' >= strlen(' . $this->input . ')) {
 145              return false; // end of input

 146          }
 147          ');
 148          fwrite($this->out, '$yy_global_pattern = "' .
 149              $pattern . '";' . "\n");
 150          fwrite($this->out, '
 151          do {
 152              if (preg_match($yy_global_pattern, substr(' . $this->input . ', ' .
 153               $this->counter .
 154                      '), $yymatches)) {
 155                  $yysubmatches = $yymatches;
 156                  $yymatches = array_filter($yymatches, \'strlen\'); // remove empty sub-patterns

 157                  if (!count($yymatches)) {
 158                      throw new Exception(\'Error: lexing failed because a rule matched\' .
 159                          \'an empty string.  Input "\' . substr(' . $this->input . ',
 160                          ' . $this->counter . ', 5) . \'... state ' . $statename . '\');
 161                  }
 162                  next($yymatches); // skip global match

 163                  ' . $this->token . ' = key($yymatches); // token number

 164                  if ($tokenMap[' . $this->token . ']) {
 165                      // extract sub-patterns for passing to lex function

 166                      $yysubmatches = array_slice($yysubmatches, ' . $this->token . ' + 1,
 167                          $tokenMap[' . $this->token . ']);
 168                  } else {
 169                      $yysubmatches = array();
 170                  }
 171                  ' . $this->value . ' = current($yymatches); // token value

 172                  $r = $this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}($yysubmatches);
 173                  if ($r === null) {
 174                      ' . $this->counter . ' += strlen($this->value);
 175                      ' . $this->line . ' += substr_count("\n", ' . $this->value . ');
 176                      // accept this token

 177                      return true;
 178                  } elseif ($r === true) {
 179                      // we have changed state

 180                      // process this token in the new state

 181                      return $this->yylex();
 182                  } elseif ($r === false) {
 183                      ' . $this->counter . ' += strlen($this->value);
 184                      ' . $this->line . ' += substr_count("\n", ' . $this->value . ');
 185                      if (' . $this->counter . ' >= strlen(' . $this->input . ')) {
 186                          return false; // end of input

 187                      }
 188                      // skip this token

 189                      continue;
 190                  } else {');
 191          fwrite($this->out, '                    $yy_yymore_patterns = array(' . "\n");
 192          for($i = 0; count($patterns); $i++) {
 193              unset($patterns[$i]);
 194              fwrite($this->out, '        ' . $ruleMap[$i] . ' => "' .
 195                  implode('|', $patterns) . "\",\n");
 196          }
 197          fwrite($this->out, '    );' . "\n");
 198          fwrite($this->out, '
 199                      // yymore is needed

 200                      do {
 201                          if (!strlen($yy_yymore_patterns[' . $this->token . '])) {
 202                              throw new Exception(\'cannot do yymore for the last token\');
 203                          }
 204                          if (preg_match($yy_yymore_patterns[' . $this->token . '],
 205                                substr(' . $this->input . ', ' . $this->counter . '), $yymatches)) {
 206                              $yymatches = array_filter($yymatches, \'strlen\'); // remove empty sub-patterns

 207                              next($yymatches); // skip global match

 208                              ' . $this->token . ' = key($yymatches); // token number

 209                              ' . $this->value . ' = current($yymatches); // token value

 210                              ' . $this->line . ' = substr_count("\n", ' . $this->value . ');
 211                          }
 212                      } while ($this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}() !== null);
 213                      // accept

 214                      ' . $this->counter . ' += strlen($this->value);
 215                      ' . $this->line . ' += substr_count("\n", ' . $this->value . ');
 216                      return true;
 217                  }
 218              } else {
 219                  throw new Exception(\'Unexpected input at line\' . ' . $this->line . ' .
 220                      \': \' . ' . $this->input . '[' . $this->counter . ']);
 221              }
 222              break;
 223          } while (true);
 224      } // end function

 225  
 226  ');
 227          if ($statename) {
 228              fwrite($this->out, '
 229      const ' . $statename . ' = ' . $ruleindex . ';
 230  ');
 231          }
 232          foreach ($rules as $i => $rule) {
 233              fwrite($this->out, '    function yy_r' . $ruleindex . '_' . $ruleMap[$i] . '($yy_subpatterns)
 234      {
 235  ' . $rule['code'] .
 236  '    }
 237  ');
 238          }
 239          $ruleindex++; // for next set of rules

 240      }
 241  
 242      function error($msg)
 243      {
 244          echo 'Error on line ' . $this->lex->line . ': ' , $msg;
 245      }
 246  
 247      function _validatePattern($pattern)
 248      {
 249          $this->_regexLexer->reset($pattern);
 250          try {
 251              while ($this->_regexLexer->yylex()) {
 252                  $this->_regexParser->doParse(
 253                      $this->_regexLexer->token, $this->_regexLexer->value);
 254              }
 255              $this->_regexParser->doParse(0, 0);
 256          } catch (PHP_LexerGenerator_Exception $e) {
 257              $this->error($e->getMessage());
 258              throw new PHP_LexerGenerator_Exception('Invalid pattern "' . $pattern . '"');
 259          }
 260          return $this->_regexParser->result;
 261      }
 262  }
 263  
 264  start ::= lexfile.
 265  
 266  lexfile ::= declare rules(B). {
 267      fwrite($this->out, '
 268      private $_yy_state = 1;
 269      private $_yy_stack = array();
 270  
 271      function yylex()
 272      {
 273          return $this->{\'yylex\' . $this->_yy_state}();
 274      }
 275  
 276      function yypushstate($state)
 277      {
 278          array_push($this->_yy_stack, $this->_yy_state);
 279          $this->_yy_state = $state;
 280      }
 281  
 282      function yypopstate()
 283      {
 284          $this->_yy_state = array_pop($this->_yy_stack);
 285      }
 286  
 287      function yybegin($state)
 288      {
 289          $this->_yy_state = $state;
 290      }
 291  
 292  ');
 293      foreach (B as $rule) {
 294          $this->outputRules($rule['rules'], $rule['statename']);
 295          if ($rule['code']) {
 296              fwrite($this->out, $rule['code']);
 297          }
 298      }
 299  }
 300  lexfile ::= declare(D) PHPCODE(B) rules(C). {
 301      fwrite($this->out, '
 302      private $_yy_state = 1;
 303      private $_yy_stack = array();
 304  
 305      function yylex()
 306      {
 307          return $this->{\'yylex\' . $this->_yy_state}();
 308      }
 309  
 310      function yypushstate($state)
 311      {
 312          array_push($this->_yy_stack, $this->_yy_state);
 313          $this->_yy_state = $state;
 314      }
 315  
 316      function yypopstate()
 317      {
 318          $this->_yy_state = array_pop($this->_yy_stack);
 319      }
 320  
 321      function yybegin($state)
 322      {
 323          $this->_yy_state = $state;
 324      }
 325  
 326  ');
 327      if (strlen(B)) {
 328          fwrite($this->out, B);
 329      }
 330      foreach (C as $rule) {
 331          $this->outputRules($rule['rules'], $rule['statename']);
 332          if ($rule['code']) {
 333              fwrite($this->out, $rule['code']);
 334          }
 335      }
 336  }
 337  lexfile ::= PHPCODE(B) declare(D) rules(C). {
 338      if (strlen(B)) {
 339          fwrite($this->out, B);
 340      }
 341      fwrite($this->out, '
 342      private $_yy_state = 1;
 343      private $_yy_stack = array();
 344  
 345      function yylex()
 346      {
 347          return $this->{\'yylex\' . $this->_yy_state}();
 348      }
 349  
 350      function yypushstate($state)
 351      {
 352          array_push($this->_yy_stack, $this->_yy_state);
 353          $this->_yy_state = $state;
 354      }
 355  
 356      function yypopstate()
 357      {
 358          $this->_yy_state = array_pop($this->_yy_stack);
 359      }
 360  
 361      function yybegin($state)
 362      {
 363          $this->_yy_state = $state;
 364      }
 365  
 366  ');
 367      foreach (C as $rule) {
 368          $this->outputRules($rule['rules'], $rule['statename']);
 369          if ($rule['code']) {
 370              fwrite($this->out, $rule['code']);
 371          }
 372      }
 373  }
 374  lexfile ::= PHPCODE(A) declare(D) PHPCODE(B) rules(C). {
 375      if (strlen(A)) {
 376          fwrite($this->out, A);
 377      }
 378      fwrite($this->out, '
 379      private $_yy_state = 1;
 380      private $_yy_stack = array();
 381  
 382      function yylex()
 383      {
 384          return $this->{\'yylex\' . $this->_yy_state}();
 385      }
 386  
 387      function yypushstate($state)
 388      {
 389          array_push($this->_yy_stack, $this->_yy_state);
 390          $this->_yy_state = $state;
 391      }
 392  
 393      function yypopstate()
 394      {
 395          $this->_yy_state = array_pop($this->_yy_stack);
 396      }
 397  
 398      function yybegin($state)
 399      {
 400          $this->_yy_state = $state;
 401      }
 402  
 403  ');
 404      if (strlen(B)) {
 405          fwrite($this->out, B);
 406      }
 407      foreach (C as $rule) {
 408          $this->outputRules($rule['rules'], $rule['statename']);
 409          if ($rule['code']) {
 410              fwrite($this->out, $rule['code']);
 411          }
 412      }
 413  }
 414  
 415  declare(A) ::= COMMENTSTART declarations(B) COMMENTEND. {
 416      A = B;
 417      $this->patterns = B['patterns'];
 418  }
 419  
 420  declarations(A) ::= processing_instructions(B) pattern_declarations(C). {
 421      $expected = array(
 422          'counter' => true,
 423          'input' => true,
 424          'token' => true,
 425          'value' => true,
 426          'line' => true,
 427      );
 428      foreach (B as $pi) {
 429          if (isset($expected[$pi['pi']])) {
 430              unset($expected[$pi['pi']]);
 431              continue;
 432          }
 433          if (count($expected)) {
 434              throw new Exception('Processing Instructions "' .
 435                  implode(', ', array_keys($expected)) . '" must be defined');
 436          }
 437      }
 438      $expected = array(
 439          'counter' => true,
 440          'input' => true,
 441          'token' => true,
 442          'value' => true,
 443          'line' => true,
 444      );
 445      foreach (B as $pi) {
 446          if (isset($expected[$pi['pi']])) {
 447              $this->{$pi['pi']} = $pi['definition'];
 448              continue;
 449          }
 450          $this->error('Unknown processing instruction %' . $pi['pi'] .
 451              ', should be one of "' . implode(', ', array_keys($expected)) . '"');
 452      }
 453      A = array('patterns' => C, 'pis' => B);
 454  }
 455  
 456  processing_instructions(A) ::= PI(B) SUBPATTERN(C). {
 457      A = array(array('pi' => B, 'definition' => C));
 458  }
 459  processing_instructions(A) ::= PI(B) CODE(C). {
 460      A = array(array('pi' => B, 'definition' => C));
 461  }
 462  processing_instructions(A) ::= processing_instructions(P) PI(B) SUBPATTERN(C). {
 463      A = P;
 464      A[] = array('pi' => B, 'definition' => C);
 465  }
 466  processing_instructions(A) ::= processing_instructions(P) PI(B) CODE(C). {
 467      A = P;
 468      A[] = array('pi' => B, 'definition' => C);
 469  }
 470  
 471  pattern_declarations(A) ::= PATTERN(B) subpattern(C). {
 472      A = array(B => C);
 473  }
 474  pattern_declarations(A) ::= pattern_declarations(B) PATTERN(C) subpattern(D). {
 475      A = B;
 476      if (isset(A[C])) {
 477          throw new Exception('Pattern "' . C . '" is already defined as "' .
 478              A[C] . '", cannot redefine as "' . D->string . '"');
 479      }
 480      A[C] = D;
 481  }
 482  
 483  rules(A) ::= COMMENTSTART rule(B) COMMENTEND. {
 484      A = array(array('rules' => B, 'code' => '', 'statename' => ''));
 485  }
 486  rules(A) ::= COMMENTSTART PI(P) SUBPATTERN(S) rule(B) COMMENTEND. {
 487      if (P != 'statename') {
 488          throw new Exception('Error: only %statename processing instruction ' .
 489              'is allowed in rule sections');
 490      }
 491      A = array(array('rules' => B, 'code' => '', 'statename' => S));
 492  }
 493  rules(A) ::= COMMENTSTART rule(B) COMMENTEND PHPCODE(C). {
 494      A = array(array('rules' => B, 'code' => C, 'statename' => ''));
 495  }
 496  rules(A) ::= COMMENTSTART PI(P) SUBPATTERN(S) rule(B) COMMENTEND PHPCODE(C). {
 497      if (P != 'statename') {
 498          throw new Exception('Error: only %statename processing instruction ' .
 499              'is allowed in rule sections');
 500      }
 501      A = array(array('rules' => B, 'code' => C, 'statename' => S));
 502  }
 503  rules(A) ::= rules(R) COMMENTSTART rule(B) COMMENTEND. {
 504      A = R;
 505      A[] = array('rules' => B, 'code' => '', 'statename' => '');
 506  }
 507  rules(A) ::= rules(R) PI(P) SUBPATTERN(S) COMMENTSTART rule(B) COMMENTEND. {
 508      if (P != 'statename') {
 509          throw new Exception('Error: only %statename processing instruction ' .
 510              'is allowed in rule sections');
 511      }
 512      A = R;
 513      A[] = array('rules' => B, 'code' => '', 'statename' => S);
 514  }
 515  rules(A) ::= rules(R) COMMENTSTART rule(B) COMMENTEND PHPCODE(C). {
 516      A = R;
 517      A[] = array('rules' => B, 'code' => C, 'statename' => '');
 518  }
 519  rules(A) ::= rules(R) COMMENTSTART PI(P) SUBPATTERN(S) rule(B) COMMENTEND PHPCODE(C). {
 520      if (P != 'statename') {
 521          throw new Exception('Error: only %statename processing instruction ' .
 522              'is allowed in rule sections');
 523      }
 524      A = R;
 525      A[] = array('rules' => B, 'code' => C, 'statename' => S);
 526  }
 527  
 528  rule(A) ::= rule_subpattern(B) CODE(C). {
 529      if (@preg_match('/' . B[0] . '/', '')) {
 530          $this->error('Rule "' . B[2] . '" can match the empty string, this will break lexing');
 531      }
 532      A = array(array('pattern' => B[1], 'code' => C, 'subpatterns' => B[3]));
 533  }
 534  rule(A) ::= rule(R) rule_subpattern(B) CODE(C).{
 535      A = R;
 536      if (@preg_match('/' . B[0] . '/', '')) {
 537          $this->error('Rule "' . B[2] . '" can match the empty string, this will break lexing');
 538      }
 539      A[] = array('pattern' => B[1], 'code' => C, 'subpatterns' => B[3]);
 540  }
 541  
 542  rule_subpattern(A) ::= QUOTE(B). {
 543      A = array(
 544          preg_quote(B, '/'),
 545          str_replace(array('\\', '"'), array('\\\\', '\\"'), preg_quote(B, '/')),
 546          '"' . str_replace('"', '\"', B) . '"', 0);
 547  }
 548  rule_subpattern(A) ::= SUBPATTERN(B). {
 549      if (!isset($this->patterns[B])) {
 550          $this->error('Undefined pattern "' . B . '" used in rules');
 551          throw new Exception('Undefined pattern "' . B . '" used in rules');
 552      }
 553      A = array($this->patterns[B]['pattern'], $this->patterns[B]->string, B, $this->patterns[B]['subpatterns']);
 554  }
 555  rule_subpattern(A) ::= rule_subpattern(B) QUOTE(C). {
 556      A = array(
 557          B[0] . preg_quote(C, '/'),
 558          B[1] . str_replace(array('\\', '"'), array('\\\\', '\\"'), preg_quote(C, '/')),
 559          B[2] . ' "' . str_replace('"', '\"', C) . '"', B[3]);
 560  }
 561  rule_subpattern(A) ::= rule_subpattern(B) SUBPATTERN(C). {
 562      if (!isset($this->patterns[C])) {
 563          $this->error('Undefined pattern "' . C . '" used in rules');
 564          throw new Exception('Undefined pattern "' . C . '" used in rules');
 565      }
 566      A = array(B[0] . $this->patterns[C]['pattern'], B[1] . $this->patterns[C]->string,
 567          B[2] . ' ' . C, B[3] + $this->patterns[C]['subpatterns']);
 568  }
 569  
 570  subpattern(A) ::= QUOTE(B). {
 571      A = new PHP_LexerGenerator_ParseryyToken(str_replace(array('\\', '"'), array('\\\\', '\\"'), preg_quote(B, '/')), array(
 572          'pattern' => preg_quote(B, '/'), 'subpatterns' => 0));
 573  }
 574  subpattern(A) ::= SUBPATTERN(B). {
 575      A = $this->_validatePattern(B);
 576  }
 577  subpattern(A) ::= subpattern(B) QUOTE(C). {
 578      A = new PHP_LexerGenerator_ParseryyToken(B->string . str_replace(array('\\', '"'), array('\\\\', '\\"'), preg_quote(C, '/')), array(
 579          'pattern' => B['pattern'] . preg_quote(C, '/'), 'subpatterns' => B['subpatterns']));
 580  }
 581  subpattern(A) ::= subpattern(B) SUBPATTERN(C). {
 582      $x = $this->_validatePattern(C);
 583      A = new PHP_LexerGenerator_ParseryyToken(B->string . $x->string, array(
 584          'pattern' => B['pattern'] . $x['pattern'],
 585          'subpatterns' => $x['subpatterns'] + B['subpatterns']));
 586  }


Generated: Fri Nov 28 20:08:37 2014 Cross-referenced by PHPXref 0.7.1