[ Index ] |
PHP Cross Reference of vtigercrm-6.1.0 |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:08:37 2014 | Cross-referenced by PHPXref 0.7.1 |