[ Index ]

PHP Cross Reference of vtigercrm-6.1.0

title

Body

[close]

/pkg/vtiger/extensions/Webservices/third-party/ParserGenerator/ -> Parser.php (source)

   1  <?php
   2  /**
   3   * PHP_ParserGenerator, a php 5 parser generator.
   4   * 
   5   * This is a direct port of the Lemon parser generator, found at
   6   * {@link http://www.hwaci.com/sw/lemon/}
   7   *
   8   * PHP version 5
   9   *
  10   * LICENSE: This source file is subject to version 3.01 of the PHP license
  11   * that is available through the world-wide-web at the following URI:
  12   * http://www.php.net/license/3_01.txt.  If you did not receive a copy of
  13   * the PHP License and are unable to obtain it through the web, please
  14   * send a note to [email protected] so we can mail you a copy immediately.
  15   *
  16   * @category   php
  17   * @package    PHP_ParserGenerator
  18   * @author     Gregory Beaver <[email protected]>
  19   * @copyright  2006 Gregory Beaver
  20   * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
  21   * @version    CVS: $Id$
  22   * @since      File available since Release 0.1.0
  23   */
  24  /**
  25   * The grammar parser for lemon grammar files.
  26   * 
  27   * @package    PHP_ParserGenerator
  28   * @author     Gregory Beaver <[email protected]>
  29   * @copyright  2006 Gregory Beaver
  30   * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
  31   * @since      Class available since Release 0.1.0
  32   */
  33  class PHP_ParserGenerator_Parser
  34  {
  35      const INITIALIZE = 1;
  36      const WAITING_FOR_DECL_OR_RULE = 2;
  37      const WAITING_FOR_DECL_KEYWORD = 3;
  38      const WAITING_FOR_DECL_ARG = 4;
  39      const WAITING_FOR_PRECEDENCE_SYMBOL = 5;
  40      const WAITING_FOR_ARROW = 6;
  41      const IN_RHS = 7;
  42      const LHS_ALIAS_1 = 8;
  43      const LHS_ALIAS_2 = 9;
  44      const LHS_ALIAS_3 = 10;
  45      const RHS_ALIAS_1 = 11;
  46      const RHS_ALIAS_2 = 12;
  47      const PRECEDENCE_MARK_1 = 13;
  48      const PRECEDENCE_MARK_2 = 14;
  49      const RESYNC_AFTER_RULE_ERROR = 15;
  50      const RESYNC_AFTER_DECL_ERROR = 16;
  51      const WAITING_FOR_DESTRUCTOR_SYMBOL = 17;
  52      const WAITING_FOR_DATATYPE_SYMBOL = 18;
  53      const WAITING_FOR_FALLBACK_ID = 19;
  54  
  55      /**
  56       * Name of the input file
  57       *
  58       * @var string
  59       */
  60      public $filename;
  61      /**
  62       * Linenumber at which current token starts
  63       * @var int
  64       */
  65      public $tokenlineno;
  66      /**
  67       * Number of parsing errors so far
  68       * @var int
  69       */
  70      public $errorcnt;
  71      /**
  72       * Index of current token within the input string
  73       * @var int
  74       */
  75      public $tokenstart;
  76      /**
  77       * Global state vector
  78       * @var PHP_ParserGenerator_Data
  79       */
  80      public $gp;
  81      /**
  82       * Parser state (one of the class constants for this class)
  83       *
  84       * - PHP_ParserGenerator_Parser::INITIALIZE,
  85       * - PHP_ParserGenerator_Parser::WAITING_FOR_DECL_OR_RULE,
  86       * - PHP_ParserGenerator_Parser::WAITING_FOR_DECL_KEYWORD,
  87       * - PHP_ParserGenerator_Parser::WAITING_FOR_DECL_ARG,
  88       * - PHP_ParserGenerator_Parser::WAITING_FOR_PRECEDENCE_SYMBOL,
  89       * - PHP_ParserGenerator_Parser::WAITING_FOR_ARROW,
  90       * - PHP_ParserGenerator_Parser::IN_RHS,
  91       * - PHP_ParserGenerator_Parser::LHS_ALIAS_1,
  92       * - PHP_ParserGenerator_Parser::LHS_ALIAS_2,
  93       * - PHP_ParserGenerator_Parser::LHS_ALIAS_3,
  94       * - PHP_ParserGenerator_Parser::RHS_ALIAS_1,
  95       * - PHP_ParserGenerator_Parser::RHS_ALIAS_2,
  96       * - PHP_ParserGenerator_Parser::PRECEDENCE_MARK_1,
  97       * - PHP_ParserGenerator_Parser::PRECEDENCE_MARK_2,
  98       * - PHP_ParserGenerator_Parser::RESYNC_AFTER_RULE_ERROR,
  99       * - PHP_ParserGenerator_Parser::RESYNC_AFTER_DECL_ERROR,
 100       * - PHP_ParserGenerator_Parser::WAITING_FOR_DESTRUCTOR_SYMBOL,
 101       * - PHP_ParserGenerator_Parser::WAITING_FOR_DATATYPE_SYMBOL,
 102       * - PHP_ParserGenerator_Parser::WAITING_FOR_FALLBACK_ID
 103       * @var int
 104       */
 105      public $state;
 106      /**
 107       * The fallback token
 108       * @var PHP_ParserGenerator_Symbol
 109       */
 110      public $fallback;
 111      /**
 112       * Left-hand side of the current rule
 113       * @var PHP_ParserGenerator_Symbol
 114       */
 115      public $lhs;
 116      /**
 117       * Alias for the LHS
 118       * @var string
 119       */
 120      public $lhsalias;
 121      /**
 122       * Number of right-hand side symbols seen
 123       * @var int
 124       */
 125      public $nrhs;
 126      /**
 127       * Right-hand side symbols
 128       * @var array array of {@link PHP_ParserGenerator_Symbol} objects
 129       */
 130      public $rhs = array();
 131      /**
 132       * Aliases for each RHS symbol name (or NULL)
 133       * @var array array of strings
 134       */
 135      public $alias = array();
 136      /**
 137       * Previous rule parsed
 138       * @var PHP_ParserGenerator_Rule
 139       */
 140      public $prevrule;
 141      /**
 142       * Keyword of a declaration
 143       * 
 144       * This is one of the %keyword keywords in the grammar file
 145       * @var string
 146       */
 147      public $declkeyword;
 148      /**
 149       * Where the declaration argument should be put
 150       *
 151       * This is assigned as a reference to an internal variable
 152       * @var mixed
 153       */
 154      public $declargslot = array();
 155      /**
 156       * Where the declaration linenumber is put
 157       * 
 158       * This is assigned as a reference to an internal variable
 159       * @var mixed
 160       */
 161      public $decllnslot;
 162      /*enum e_assoc*/
 163      public $declassoc;    /* Assign this association to decl arguments */
 164      public $preccounter;           /* Assign this precedence to decl arguments */
 165      /**
 166       * @var PHP_ParserGenerator_Rule
 167       */
 168      public $firstrule;    /* Pointer to first rule in the grammar */
 169      /**
 170       * @var PHP_ParserGenerator_Rule
 171       */
 172      public $lastrule;     /* Pointer to the most recently parsed rule */
 173  
 174      /**
 175       * @var PHP_ParserGenerator
 176       */
 177      private $lemon;
 178  
 179      function __construct(PHP_ParserGenerator $lem)
 180      {
 181          $this->lemon = $lem;
 182      }
 183  
 184      /**
 185       * Run the preprocessor over the input file text.  The Lemon variable
 186       * $azDefine contains the names of all defined
 187       * macros.  This routine looks for "%ifdef" and "%ifndef" and "%endif" and
 188       * comments them out.  Text in between is also commented out as appropriate.
 189       * @param string
 190       */
 191      private function preprocess_input(&$z)
 192      {
 193          $lineno = $exclude = 0;
 194          for ($i=0; $i < strlen($z); $i++) {
 195              if ($z[$i] == "\n") {
 196                  $lineno++;
 197              }
 198              if ($z[$i] != '%' || ($i > 0 && $z[$i-1] != "\n")) {
 199                  continue;
 200              }
 201              if (substr($z, $i, 6) === "%endif" && trim($z[$i+6]) === '') {
 202                  if ($exclude) {
 203                      $exclude--;
 204                      if ($exclude === 0) {
 205                          for ($j = $start; $j < $i; $j++) {
 206                              if ($z[$j] != "\n") $z[$j] = ' ';
 207                          }
 208                      }
 209                  }
 210                  for ($j = $i; $j < strlen($z) && $z[$j] != "\n"; $j++) {
 211                      $z[$j] = ' ';
 212                  }
 213              } elseif (substr($z, $i, 6) === "%ifdef" && trim($z[$i+6]) === '' ||
 214                        substr($z, $i, 7) === "%ifndef" && trim($z[$i+7]) === '') {
 215                  if ($exclude) {
 216                      $exclude++;
 217                  } else {
 218                      $j = $i;
 219                      $n = strtok(substr($z, $j), " \t");
 220                      $exclude = 1;
 221                      if (isset($this->lemon->azDefine[$n])) {
 222                          $exclude = 0;
 223                      }
 224                      if ($z[$i + 3]=='n') {
 225                          // this is a rather obtuse way of checking whether this is %ifndef
 226                          $exclude = !$exclude;
 227                      }
 228                      if ($exclude) {
 229                          $start = $i;
 230                          $start_lineno = $lineno;
 231                      }
 232                  }
 233                  //for ($j = $i; $j < strlen($z) && $z[$j] != "\n"; $j++) $z[$j] = ' ';
 234                  $j = strpos(substr($z, $i), "\n");
 235                  if ($j === false) {
 236                      $z = substr($z, 0, $i); // remove instead of adding ' '
 237                  } else {
 238                      $z = substr($z, 0, $i) . substr($z, $i + $j); // remove instead of adding ' '
 239                  }
 240              }
 241          }
 242          if ($exclude) {
 243              throw new Exception("unterminated %ifdef starting on line $start_lineno\n");
 244          }
 245      }
 246  
 247      /**
 248       * In spite of its name, this function is really a scanner.
 249       * 
 250       * It reads in the entire input file (all at once) then tokenizes it.
 251       * Each token is passed to the function "parseonetoken" which builds all
 252       * the appropriate data structures in the global state vector "gp".
 253       * @param PHP_ParserGenerator_Data
 254       */
 255      function Parse(PHP_ParserGenerator_Data $gp)
 256      {
 257          $startline = 0;
 258      
 259          $this->gp = $gp;
 260          $this->filename = $gp->filename;
 261          $this->errorcnt = 0;
 262          $this->state = self::INITIALIZE;
 263      
 264          /* Begin by reading the input file */
 265          $filebuf = file_get_contents($this->filename);
 266          if (!$filebuf) {
 267              PHP_ParserGenerator::ErrorMsg($this->filename, 0, "Can't open this file for reading.");
 268              $gp->errorcnt++;
 269              return;
 270          }
 271          if (filesize($this->filename) != strlen($filebuf)) {
 272              ErrorMsg($this->filename, 0, "Can't read in all %d bytes of this file.",
 273                  filesize($this->filename));
 274              $gp->errorcnt++;
 275              return;
 276          }
 277  
 278          /* Make an initial pass through the file to handle %ifdef and %ifndef */
 279          $this->preprocess_input($filebuf);
 280      
 281          /* Now scan the text of the input file */
 282          $lineno = 1;
 283          for ($cp = 0, $c = $filebuf[0]; $cp < strlen($filebuf); $cp++) {
 284              $c = $filebuf[$cp];
 285              if ($c == "\n") $lineno++;              /* Keep track of the line number */
 286              if (trim($c) === '') {
 287                  continue;
 288              }  /* Skip all white space */
 289              if ($filebuf[$cp] == '/' && ($cp + 1 < strlen($filebuf)) && $filebuf[$cp + 1] == '/') {
 290                  /* Skip C++ style comments */
 291                  $cp += 2;
 292                  $z = strpos(substr($filebuf, $cp), "\n");
 293                  if ($z === false) {
 294                      $cp = strlen($filebuf);
 295                      break;
 296                  }
 297                  $lineno++;
 298                  $cp += $z;
 299                  continue;
 300              }
 301              if ($filebuf[$cp] == '/' && ($cp + 1 < strlen($filebuf)) && $filebuf[$cp + 1] == '*') {
 302                  /* Skip C style comments */
 303                  $cp += 2;
 304                  $z = strpos(substr($filebuf, $cp), '*/');
 305                  if ($z !== false) {
 306                      $lineno += count(explode("\n", substr($filebuf, $cp, $z))) - 1;
 307                  }
 308                  $cp += $z + 1;
 309                  continue;
 310              }
 311              $this->tokenstart = $cp;                /* Mark the beginning of the token */
 312              $this->tokenlineno = $lineno;           /* Linenumber on which token begins */
 313              if ($filebuf[$cp] == '"') {                     /* String literals */
 314                  $cp++;
 315                  $oldcp = $cp;
 316                  $test = strpos(substr($filebuf, $cp), '"');
 317                  if ($test === false) {
 318                      PHP_ParserGenerator::ErrorMsg($this->filename, $startline,
 319                      "String starting on this line is not terminated before the end of the file.");
 320                      $this->errorcnt++;
 321                      $nextcp = $cp = strlen($filebuf);
 322                  } else {
 323                      $cp += $test;
 324                      $nextcp = $cp + 1;
 325                  }
 326                  $lineno += count(explode("\n", substr($filebuf, $oldcp, $cp - $oldcp))) - 1;
 327              } elseif ($filebuf[$cp] == '{') {               /* A block of C code */
 328                  $cp++;
 329                  for ($level = 1; $cp < strlen($filebuf) && ($level > 1 || $filebuf[$cp] != '}'); $cp++) {
 330                      if ($filebuf[$cp] == "\n") {
 331                          $lineno++;
 332                      } elseif ($filebuf[$cp] == '{') {
 333                          $level++;
 334                      } elseif ($filebuf[$cp] == '}') {
 335                          $level--;
 336                      } elseif ($filebuf[$cp] == '/' && $filebuf[$cp + 1] == '*') {
 337                          /* Skip comments */
 338                          $cp += 2;
 339                          $z = strpos(substr($filebuf, $cp), '*/');
 340                          if ($z !== false) {
 341                              $lineno += count(explode("\n", substr($filebuf, $cp, $z))) - 1;
 342                          }
 343                          $cp += $z + 2;
 344                      } elseif ($filebuf[$cp] == '/' && $filebuf[$cp + 1] == '/') {
 345                          /* Skip C++ style comments too */
 346                          $cp += 2;
 347                          $z = strpos(substr($filebuf, $cp), "\n");
 348                          if ($z === false) {
 349                              $cp = strlen($filebuf);
 350                              break;
 351                          } else {
 352                              $lineno++;
 353                          }
 354                          $cp += $z;
 355                      } elseif ($filebuf[$cp] == "'" || $filebuf[$cp] == '"') {
 356                          /* String a character literals */
 357                          $startchar = $filebuf[$cp];
 358                          $prevc = 0;
 359                          for ($cp++; $cp < strlen($filebuf) && ($filebuf[$cp] != $startchar || $prevc === '\\'); $cp++) {
 360                              if ($filebuf[$cp] == "\n") {
 361                                  $lineno++;
 362                              }
 363                              if ($prevc === '\\') {
 364                                  $prevc = 0;
 365                              } else {
 366                                  $prevc = $filebuf[$cp];
 367                              }
 368                          }
 369                      }
 370                  }
 371                  if ($cp >= strlen($filebuf)) {
 372                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 373                          "PHP code starting on this line is not terminated before the end of the file.");
 374                      $this->errorcnt++;
 375                      $nextcp = $cp;
 376                  } else {
 377                      $nextcp = $cp + 1;
 378                  }
 379              } elseif (preg_match('/[a-zA-Z0-9]/', $filebuf[$cp])) {
 380                  /* Identifiers */
 381                  preg_match('/[a-zA-Z0-9_]+/', substr($filebuf, $cp), $preg_results);
 382                  $cp += strlen($preg_results[0]);
 383                  $nextcp = $cp;
 384              } elseif ($filebuf[$cp] == ':' && $filebuf[$cp + 1] == ':' &&
 385                        $filebuf[$cp + 2] == '=') {
 386                  /* The operator "::=" */
 387                  $cp += 3;
 388                  $nextcp = $cp;
 389              } elseif (($filebuf[$cp] == '/' || $filebuf[$cp] == '|') &&
 390                        preg_match('/[a-zA-Z]/', $filebuf[$cp + 1])) {
 391                  $cp += 2;
 392                  preg_match('/[a-zA-Z0-9_]+/', substr($filebuf, $cp), $preg_results);
 393                  $cp += strlen($preg_results[0]);
 394                  $nextcp = $cp;
 395              } else {
 396                  /* All other (one character) operators */
 397                  $cp ++;
 398                  $nextcp = $cp;
 399              }
 400              $this->parseonetoken(substr($filebuf, $this->tokenstart,
 401                  $cp - $this->tokenstart)); /* Parse the token */
 402              $cp = $nextcp - 1;
 403          }
 404          $gp->rule = $this->firstrule;
 405          $gp->errorcnt = $this->errorcnt;
 406      }
 407  
 408      /**
 409       * Parse a single token
 410       * @param string token
 411       */
 412      function parseonetoken($token)
 413      {
 414          $x = $token;
 415          $this->a = 0; // for referencing in WAITING_FOR_DECL_KEYWORD
 416          if (PHP_ParserGenerator::DEBUG) {
 417              printf("%s:%d: Token=[%s] state=%d\n",
 418                  $this->filename, $this->tokenlineno, $token, $this->state);
 419          }
 420          switch ($this->state) {
 421              case self::INITIALIZE:
 422                  $this->prevrule = 0;
 423                  $this->preccounter = 0;
 424                  $this->firstrule = $this->lastrule = 0;
 425                  $this->gp->nrule = 0;
 426                  /* Fall thru to next case */
 427              case self::WAITING_FOR_DECL_OR_RULE:
 428                  if ($x[0] == '%') {
 429                      $this->state = self::WAITING_FOR_DECL_KEYWORD;
 430                  } elseif (preg_match('/[a-z]/', $x[0])) {
 431                      $this->lhs = PHP_ParserGenerator_Symbol::Symbol_new($x);
 432                      $this->nrhs = 0;
 433                      $this->lhsalias = 0;
 434                      $this->state = self::WAITING_FOR_ARROW;
 435                  } elseif ($x[0] == '{') {
 436                      if ($this->prevrule === 0) {
 437                          PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 438                              "There is no prior rule opon which to attach the code
 439                               fragment which begins on this line.");
 440                          $this->errorcnt++;
 441                      } elseif ($this->prevrule->code != 0) {
 442                          PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 443                              "Code fragment beginning on this line is not the first \
 444                               to follow the previous rule.");
 445                          $this->errorcnt++;
 446                      } else {
 447                          $this->prevrule->line = $this->tokenlineno;
 448                          $this->prevrule->code = substr($x, 1);
 449                      }
 450                  } elseif ($x[0] == '[') {
 451                      $this->state = self::PRECEDENCE_MARK_1;
 452                  } else {
 453                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 454                      "Token \"%s\" should be either \"%%\" or a nonterminal name.",
 455                      $x);
 456                      $this->errorcnt++;
 457                  }
 458                  break;
 459              case self::PRECEDENCE_MARK_1:
 460                  if (!preg_match('/[A-Z]/', $x[0])) {
 461                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 462                          "The precedence symbol must be a terminal.");
 463                      $this->errorcnt++;
 464                  } elseif ($this->prevrule === 0) {
 465                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 466                          "There is no prior rule to assign precedence \"[%s]\".", $x);
 467                      $this->errorcnt++;
 468                  } elseif ($this->prevrule->precsym != 0) {
 469                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 470                          "Precedence mark on this line is not the first to follow the previous rule.");
 471                      $this->errorcnt++;
 472                  } else {
 473                      $this->prevrule->precsym = PHP_ParserGenerator_Symbol::Symbol_new($x);
 474                  }
 475                  $this->state = self::PRECEDENCE_MARK_2;
 476                  break;
 477              case self::PRECEDENCE_MARK_2:
 478                  if ($x[0] != ']') {
 479                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 480                          "Missing \"]\" on precedence mark.");
 481                      $this->errorcnt++;
 482                  }
 483                  $this->state = self::WAITING_FOR_DECL_OR_RULE;
 484                  break;
 485              case self::WAITING_FOR_ARROW:
 486                  if ($x[0] == ':' && $x[1] == ':' && $x[2] == '=') {
 487                      $this->state = self::IN_RHS;
 488                  } elseif ($x[0] == '(') {
 489                      $this->state = self::LHS_ALIAS_1;
 490                  } else {
 491                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 492                          "Expected to see a \":\" following the LHS symbol \"%s\".",
 493                      $this->lhs->name);
 494                      $this->errorcnt++;
 495                      $this->state = self::RESYNC_AFTER_RULE_ERROR;
 496                  }
 497                  break;
 498              case self::LHS_ALIAS_1:
 499                  if (preg_match('/[A-Za-z]/', $x[0])) {
 500                      $this->lhsalias = $x;
 501                      $this->state = self::LHS_ALIAS_2;
 502                  } else {
 503                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 504                          "\"%s\" is not a valid alias for the LHS \"%s\"\n",
 505                          $x, $this->lhs->name);
 506                      $this->errorcnt++;
 507                      $this->state = self::RESYNC_AFTER_RULE_ERROR;
 508                  }
 509                  break;
 510              case self::LHS_ALIAS_2:
 511                  if ($x[0] == ')') {
 512                      $this->state = self::LHS_ALIAS_3;
 513                  } else {
 514                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 515                          "Missing \")\" following LHS alias name \"%s\".",$this->lhsalias);
 516                      $this->errorcnt++;
 517                      $this->state = self::RESYNC_AFTER_RULE_ERROR;
 518                  }
 519                  break;
 520              case self::LHS_ALIAS_3:
 521                  if ($x == '::=') {
 522                      $this->state = self::IN_RHS;
 523                  } else {
 524                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 525                          "Missing \"->\" following: \"%s(%s)\".",
 526                      $this->lhs->name, $this->lhsalias);
 527                      $this->errorcnt++;
 528                      $this->state = self::RESYNC_AFTER_RULE_ERROR;
 529                  }
 530                  break;
 531              case self::IN_RHS:
 532                  if ($x[0] == '.') {
 533                      $rp = new PHP_ParserGenerator_Rule;
 534                      $rp->ruleline = $this->tokenlineno;
 535                      for ($i = 0; $i < $this->nrhs; $i++) {
 536                          $rp->rhs[$i] = $this->rhs[$i];
 537                          $rp->rhsalias[$i] = $this->alias[$i];
 538                      }
 539                      $rp->lhs = $this->lhs;
 540                      $rp->lhsalias = $this->lhsalias;
 541                      $rp->nrhs = $this->nrhs;
 542                      $rp->code = 0;
 543                      $rp->precsym = 0;
 544                      $rp->index = $this->gp->nrule++;
 545                      $rp->nextlhs = $rp->lhs->rule;
 546                      $rp->lhs->rule = $rp;
 547                      $rp->next = 0;
 548                      if ($this->firstrule === 0) {
 549                          $this->firstrule = $this->lastrule = $rp;
 550                      } else {
 551                          $this->lastrule->next = $rp;
 552                          $this->lastrule = $rp;
 553                      }
 554                      $this->prevrule = $rp;
 555                      $this->state = self::WAITING_FOR_DECL_OR_RULE;
 556                  } elseif (preg_match('/[a-zA-Z]/', $x[0])) {
 557                      if ($this->nrhs >= PHP_ParserGenerator::MAXRHS) {
 558                          PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 559                              "Too many symbols on RHS or rule beginning at \"%s\".",
 560                              $x);
 561                          $this->errorcnt++;
 562                          $this->state = self::RESYNC_AFTER_RULE_ERROR;
 563                      } else {
 564                          if (isset($this->rhs[$this->nrhs - 1])) {
 565                              $msp = $this->rhs[$this->nrhs - 1];
 566                              if ($msp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL) {
 567                                  $inf = array_reduce($msp->subsym,
 568                                      array($this, '_printmulti'), '');
 569                                  PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 570                                      'WARNING: symbol ' . $x . ' will not' .
 571                                      ' be part of previous multiterminal %s',
 572                                      substr($inf, 0, strlen($inf) - 1)
 573                                      );
 574                              }
 575                          }
 576                          $this->rhs[$this->nrhs] = PHP_ParserGenerator_Symbol::Symbol_new($x);
 577                          $this->alias[$this->nrhs] = 0;
 578                          $this->nrhs++;
 579                      }
 580                  } elseif (($x[0] == '|' || $x[0] == '/') && $this->nrhs > 0) {
 581                      $msp = $this->rhs[$this->nrhs - 1];
 582                      if ($msp->type != PHP_ParserGenerator_Symbol::MULTITERMINAL) {
 583                          $origsp = $msp;
 584                          $msp = new PHP_ParserGenerator_Symbol;
 585                          $msp->type = PHP_ParserGenerator_Symbol::MULTITERMINAL;
 586                          $msp->nsubsym = 1;
 587                          $msp->subsym = array($origsp);
 588                          $msp->name = $origsp->name;
 589                          $this->rhs[$this->nrhs - 1] = $msp;
 590                      }
 591                      $msp->nsubsym++;
 592                      $msp->subsym[$msp->nsubsym - 1] = PHP_ParserGenerator_Symbol::Symbol_new(substr($x, 1));
 593                      if (preg_match('/[a-z]/', $x[1]) ||
 594                            preg_match('/[a-z]/', $msp->subsym[0]->name[0])) {
 595                          PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 596                          "Cannot form a compound containing a non-terminal");
 597                          $this->errorcnt++;
 598                      }
 599                  } elseif ($x[0] == '(' && $this->nrhs > 0) {
 600                      $this->state = self::RHS_ALIAS_1;
 601                  } else {
 602                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 603                          "Illegal character on RHS of rule: \"%s\".", $x);
 604                      $this->errorcnt++;
 605                      $this->state = self::RESYNC_AFTER_RULE_ERROR;
 606                  }
 607                  break;
 608              case self::RHS_ALIAS_1:
 609                  if (preg_match('/[A-Za-z]/', $x[0])) {
 610                      $this->alias[$this->nrhs - 1] = $x;
 611                      $this->state = self::RHS_ALIAS_2;
 612                  } else {
 613                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 614                          "\"%s\" is not a valid alias for the RHS symbol \"%s\"\n",
 615                          $x, $this->rhs[$this->nrhs - 1]->name);
 616                      $this->errorcnt++;
 617                      $this->state = self::RESYNC_AFTER_RULE_ERROR;
 618                  }
 619                  break;
 620              case self::RHS_ALIAS_2:
 621                  if ($x[0] == ')') {
 622                      $this->state = self::IN_RHS;
 623                  } else {
 624                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 625                          "Missing \")\" following LHS alias name \"%s\".", $this->lhsalias);
 626                      $this->errorcnt++;
 627                      $this->state = self::RESYNC_AFTER_RULE_ERROR;
 628                  }
 629                  break;
 630              case self::WAITING_FOR_DECL_KEYWORD:
 631                  if(preg_match('/[A-Za-z]/', $x[0])) {
 632                      $this->declkeyword = $x;
 633                      $this->declargslot = &$this->a;
 634                      $this->decllnslot = &$this->a;
 635                      $this->state = self::WAITING_FOR_DECL_ARG;
 636                      if ('name' == $x) {
 637                          $this->declargslot = &$this->gp->name;
 638                      } elseif ('include' == $x) {
 639                          $this->declargslot = &$this->gp->include_code;
 640                          $this->decllnslot = &$this->gp->includeln;
 641                      } elseif ('include_class' == $x) {
 642                          $this->declargslot = &$this->gp->include_classcode;
 643                          $this->decllnslot = &$this->gp->include_classln;
 644                      } elseif ('declare_class' == $x) {
 645                          $this->declargslot = &$this->gp->declare_classcode;
 646                          $this->decllnslot = &$this->gp->declare_classln;
 647                      } elseif ('code' == $x) {
 648                          $this->declargslot = &$this->gp->extracode;
 649                          $this->decllnslot = &$this->gp->extracodeln;
 650                      } elseif ('token_destructor' == $x) {
 651                          $this->declargslot = &$this->gp->tokendest;
 652                          $this->decllnslot = &$this->gp->tokendestln;
 653                      } elseif ('default_destructor' == $x) {
 654                          $this->declargslot = &$this->gp->vardest;
 655                          $this->decllnslot = &$this->gp->vardestln;
 656                      } elseif ('token_prefix' == $x) {
 657                          $this->declargslot = &$this->gp->tokenprefix;
 658                      } elseif ('syntax_error' == $x) {
 659                          $this->declargslot = &$this->gp->error;
 660                          $this->decllnslot = &$this->gp->errorln;
 661                      } elseif ('parse_accept' == $x) {
 662                          $this->declargslot = &$this->gp->accept;
 663                          $this->decllnslot = &$this->gp->acceptln;
 664                      } elseif ('parse_failure' == $x) {
 665                          $this->declargslot = &$this->gp->failure;
 666                          $this->decllnslot = &$this->gp->failureln;
 667                      } elseif ('stack_overflow' == $x) {
 668                          $this->declargslot = &$this->gp->overflow;
 669                          $this->decllnslot = &$this->gp->overflowln;
 670                      } elseif ('token_type' == $x) {
 671                          $this->declargslot = &$this->gp->tokentype;
 672                      } elseif ('default_type' == $x) {
 673                          $this->declargslot = &$this->gp->vartype;
 674                      } elseif ('stack_size' == $x) {
 675                          $this->declargslot = &$this->gp->stacksize;
 676                      } elseif ('start_symbol' == $x) {
 677                          $this->declargslot = &$this->gp->start;
 678                      } elseif ('left' == $x) {
 679                          $this->preccounter++;
 680                          $this->declassoc = PHP_ParserGenerator_Symbol::LEFT;
 681                          $this->state = self::WAITING_FOR_PRECEDENCE_SYMBOL;
 682                      } elseif ('right' == $x) {
 683                          $this->preccounter++;
 684                          $this->declassoc = PHP_ParserGenerator_Symbol::RIGHT;
 685                          $this->state = self::WAITING_FOR_PRECEDENCE_SYMBOL;
 686                      } elseif ('nonassoc' == $x) {
 687                          $this->preccounter++;
 688                          $this->declassoc = PHP_ParserGenerator_Symbol::NONE;
 689                          $this->state = self::WAITING_FOR_PRECEDENCE_SYMBOL;
 690                      } elseif ('destructor' == $x) {
 691                          $this->state = self::WAITING_FOR_DESTRUCTOR_SYMBOL;
 692                      } elseif ('type' == $x) {
 693                          $this->state = self::WAITING_FOR_DATATYPE_SYMBOL;
 694                      } elseif ('fallback' == $x) {
 695                          $this->fallback = 0;
 696                          $this->state = self::WAITING_FOR_FALLBACK_ID;
 697                      } else {
 698                          PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 699                          "Unknown declaration keyword: \"%%%s\".", $x);
 700                          $this->errorcnt++;
 701                          $this->state = self::RESYNC_AFTER_DECL_ERROR;
 702                      }
 703                  } else {
 704                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 705                          "Illegal declaration keyword: \"%s\".", $x);
 706                      $this->errorcnt++;
 707                      $this->state = self::RESYNC_AFTER_DECL_ERROR;
 708                  }
 709                  break;
 710              case self::WAITING_FOR_DESTRUCTOR_SYMBOL:
 711                  if (!preg_match('/[A-Za-z]/', $x[0])) {
 712                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 713                          "Symbol name missing after %destructor keyword");
 714                      $this->errorcnt++;
 715                      $this->state = self::RESYNC_AFTER_DECL_ERROR;
 716                  } else {
 717                      $sp = PHP_ParserGenerator_Symbol::Symbol_new($x);
 718                      $this->declargslot = &$sp->destructor;
 719                      $this->decllnslot = &$sp->destructorln;
 720                      $this->state = self::WAITING_FOR_DECL_ARG;
 721                  }
 722                  break;
 723              case self::WAITING_FOR_DATATYPE_SYMBOL:
 724                  if (!preg_match('/[A-Za-z]/', $x[0])) {
 725                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 726                          "Symbol name missing after %destructor keyword");
 727                      $this->errorcnt++;
 728                      $this->state = self::RESYNC_AFTER_DECL_ERROR;
 729                  } else {
 730                      $sp = PHP_ParserGenerator_Symbol::Symbol_new($x);
 731                      $this->declargslot = &$sp->datatype;
 732                      $this->state = self::WAITING_FOR_DECL_ARG;
 733                  }
 734                  break;
 735              case self::WAITING_FOR_PRECEDENCE_SYMBOL:
 736                  if ($x[0] == '.') {
 737                      $this->state = self::WAITING_FOR_DECL_OR_RULE;
 738                  } elseif (preg_match('/[A-Z]/', $x[0])) {
 739                      $sp = PHP_ParserGenerator_Symbol::Symbol_new($x);
 740                      if ($sp->prec >= 0) {
 741                          PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 742                              "Symbol \"%s\" has already been given a precedence.", $x);
 743                          $this->errorcnt++;
 744                      } else {
 745                          $sp->prec = $this->preccounter;
 746                          $sp->assoc = $this->declassoc;
 747                      }
 748                  } else {
 749                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 750                          "Can't assign a precedence to \"%s\".", $x);
 751                      $this->errorcnt++;
 752                  }
 753                  break;
 754              case self::WAITING_FOR_DECL_ARG:
 755                  if (preg_match('/[A-Za-z0-9{"]/', $x[0])) {
 756                      if ($this->declargslot != 0) {
 757                          PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 758                              "The argument \"%s\" to declaration \"%%%s\" is not the first.",
 759                              $x[0] == '"' ? substr($x, 1) : $x, $this->declkeyword);
 760                          $this->errorcnt++;
 761                          $this->state = self::RESYNC_AFTER_DECL_ERROR;
 762                      } else {
 763                          $this->declargslot = ($x[0] == '"' || $x[0] == '{') ? substr($x, 1) : $x;
 764                          $this->a = 1;
 765                          if (!$this->decllnslot) {
 766                              $this->decllnslot = $this->tokenlineno;
 767                          }
 768                          $this->state = self::WAITING_FOR_DECL_OR_RULE;
 769                      }
 770                  } else {
 771                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 772                          "Illegal argument to %%%s: %s",$this->declkeyword, $x);
 773                      $this->errorcnt++;
 774                      $this->state = self::RESYNC_AFTER_DECL_ERROR;
 775                  }
 776                  break;
 777              case self::WAITING_FOR_FALLBACK_ID:
 778                  if ($x[0] == '.') {
 779                      $this->state = self::WAITING_FOR_DECL_OR_RULE;
 780                  } elseif (!preg_match('/[A-Z]/', $x[0])) {
 781                      PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 782                      "%%fallback argument \"%s\" should be a token", $x);
 783                      $this->errorcnt++;
 784                  } else {
 785                      $sp = PHP_ParserGenerator_Symbol::Symbol_new($x);
 786                      if ($this->fallback === 0) {
 787                          $this->fallback = $sp;
 788                      } elseif (is_object($sp->fallback)) {
 789                          PHP_ParserGenerator::ErrorMsg($this->filename, $this->tokenlineno,
 790                          "More than one fallback assigned to token %s", $x);
 791                          $this->errorcnt++;
 792                      } else {
 793                          $sp->fallback = $this->fallback;
 794                          $this->gp->has_fallback = 1;
 795                      }
 796                  }
 797                  break;
 798              case self::RESYNC_AFTER_RULE_ERROR:
 799              /*      if ($x[0] == '.') $this->state = self::WAITING_FOR_DECL_OR_RULE;
 800              **      break; */
 801              case self::RESYNC_AFTER_DECL_ERROR:
 802                  if ($x[0] == '.') {
 803                      $this->state = self::WAITING_FOR_DECL_OR_RULE;
 804                  }
 805                  if ($x[0] == '%') {
 806                      $this->state = self::WAITING_FOR_DECL_KEYWORD;
 807                  }
 808                  break;
 809          }
 810      }
 811  
 812      /**
 813       * return a descriptive string for a multi-terminal token.
 814       *
 815       * @param string $a
 816       * @param string $b
 817       * @return string
 818       */
 819      private function _printmulti($a, $b)
 820      {
 821          if (!$a) {
 822              $a = '';
 823          }
 824          $a .= $b->name . '|';
 825          return $a;
 826      }
 827  }


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