Parser.php 76 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994
  1. <?php
  2. /* Driver template for the PHP_PHP_LexerGenerator_ParserrGenerator parser generator. (PHP port of LEMON)
  3. */
  4. /**
  5. * This can be used to store both the string representation of
  6. * a token, and any useful meta-data associated with the token.
  7. *
  8. * meta-data should be stored as an array
  9. */
  10. class PHP_LexerGenerator_ParseryyToken implements ArrayAccess
  11. {
  12. public $string = '';
  13. public $metadata = array();
  14. function __construct($s, $m = array())
  15. {
  16. if ($s instanceof PHP_LexerGenerator_ParseryyToken) {
  17. $this->string = $s->string;
  18. $this->metadata = $s->metadata;
  19. } else {
  20. $this->string = (string) $s;
  21. if ($m instanceof PHP_LexerGenerator_ParseryyToken) {
  22. $this->metadata = $m->metadata;
  23. } elseif (is_array($m)) {
  24. $this->metadata = $m;
  25. }
  26. }
  27. }
  28. function __toString()
  29. {
  30. return $this->_string;
  31. }
  32. function offsetExists($offset)
  33. {
  34. return isset($this->metadata[$offset]);
  35. }
  36. function offsetGet($offset)
  37. {
  38. return $this->metadata[$offset];
  39. }
  40. function offsetSet($offset, $value)
  41. {
  42. if ($offset === null) {
  43. if (isset($value[0])) {
  44. $x = ($value instanceof PHP_LexerGenerator_ParseryyToken) ?
  45. $value->metadata : $value;
  46. $this->metadata = array_merge($this->metadata, $x);
  47. return;
  48. }
  49. $offset = count($this->metadata);
  50. }
  51. if ($value === null) {
  52. return;
  53. }
  54. if ($value instanceof PHP_LexerGenerator_ParseryyToken) {
  55. if ($value->metadata) {
  56. $this->metadata[$offset] = $value->metadata;
  57. }
  58. } elseif ($value) {
  59. $this->metadata[$offset] = $value;
  60. }
  61. }
  62. function offsetUnset($offset)
  63. {
  64. unset($this->metadata[$offset]);
  65. }
  66. }
  67. /** The following structure represents a single element of the
  68. * parser's stack. Information stored includes:
  69. *
  70. * + The state number for the parser at this level of the stack.
  71. *
  72. * + The value of the token stored at this level of the stack.
  73. * (In other words, the "major" token.)
  74. *
  75. * + The semantic value stored at this level of the stack. This is
  76. * the information used by the action routines in the grammar.
  77. * It is sometimes called the "minor" token.
  78. */
  79. class PHP_LexerGenerator_ParseryyStackEntry
  80. {
  81. public $stateno; /* The state-number */
  82. public $major; /* The major token value. This is the code
  83. ** number for the token at this stack level */
  84. public $minor; /* The user-supplied minor token value. This
  85. ** is the value of the token */
  86. };
  87. // code external to the class is included here
  88. #line 3 "Parser.y"
  89. /* ?><?php {//*/
  90. /**
  91. * PHP_LexerGenerator, a php 5 lexer generator.
  92. *
  93. * This lexer generator translates a file in a format similar to
  94. * re2c ({@link http://re2c.org}) and translates it into a PHP 5-based lexer
  95. *
  96. * PHP version 5
  97. *
  98. * LICENSE:
  99. *
  100. * Copyright (c) 2006, Gregory Beaver <cellog@php.net>
  101. * All rights reserved.
  102. *
  103. * Redistribution and use in source and binary forms, with or without
  104. * modification, are permitted provided that the following conditions
  105. * are met:
  106. *
  107. * * Redistributions of source code must retain the above copyright
  108. * notice, this list of conditions and the following disclaimer.
  109. * * Redistributions in binary form must reproduce the above copyright
  110. * notice, this list of conditions and the following disclaimer in
  111. * the documentation and/or other materials provided with the distribution.
  112. * * Neither the name of the PHP_LexerGenerator nor the names of its
  113. * contributors may be used to endorse or promote products derived
  114. * from this software without specific prior written permission.
  115. *
  116. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  117. * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  118. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  119. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  120. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  121. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  122. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  123. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  124. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  125. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  126. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  127. *
  128. * @category php
  129. * @package PHP_LexerGenerator
  130. * @author Gregory Beaver <cellog@php.net>
  131. * @copyright 2006 Gregory Beaver
  132. * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
  133. * @version CVS: $Id: Parser.php 246683 2007-11-22 04:43:52Z instance $
  134. * @since File available since Release 0.1.0
  135. */
  136. /**
  137. * For regular expression validation
  138. */
  139. require_once 'PHP/LexerGenerator/Regex/Lexer.php';
  140. require_once 'PHP/LexerGenerator/Regex/Parser.php';
  141. require_once 'PHP/LexerGenerator/Exception.php';
  142. /**
  143. * Token parser for plex files.
  144. *
  145. * This parser converts tokens pulled from {@link PHP_LexerGenerator_Lexer}
  146. * into abstract patterns and rules, then creates the output file
  147. * @package PHP_LexerGenerator
  148. * @author Gregory Beaver <cellog@php.net>
  149. * @copyright 2006 Gregory Beaver
  150. * @license http://www.php.net/license/3_01.txt PHP License 3.01
  151. * @version @package_version@
  152. * @since Class available since Release 0.1.0
  153. */
  154. #line 166 "Parser.php"
  155. // declare_class is output here
  156. #line 2 "Parser.y"
  157. class PHP_LexerGenerator_Parser#line 171 "Parser.php"
  158. {
  159. /* First off, code is included which follows the "include_class" declaration
  160. ** in the input file. */
  161. #line 82 "Parser.y"
  162. private $patterns;
  163. private $out;
  164. private $lex;
  165. private $input;
  166. private $counter;
  167. private $token;
  168. private $value;
  169. private $line;
  170. private $matchlongest;
  171. private $_regexLexer;
  172. private $_regexParser;
  173. private $_patternIndex = 0;
  174. private $_outRuleIndex = 1;
  175. private $caseinsensitive;
  176. private $patternFlags;
  177. private $unicode;
  178. public $transTable = array(
  179. 1 => self::PHPCODE,
  180. 2 => self::COMMENTSTART,
  181. 3 => self::COMMENTEND,
  182. 4 => self::QUOTE,
  183. 5 => self::SINGLEQUOTE,
  184. 6 => self::PATTERN,
  185. 7 => self::CODE,
  186. 8 => self::SUBPATTERN,
  187. 9 => self::PI,
  188. );
  189. function __construct($outfile, $lex)
  190. {
  191. $this->out = fopen($outfile, 'wb');
  192. if (!$this->out) {
  193. throw new Exception('unable to open lexer output file "' . $outfile . '"');
  194. }
  195. $this->lex = $lex;
  196. $this->_regexLexer = new PHP_LexerGenerator_Regex_Lexer('');
  197. $this->_regexParser = new PHP_LexerGenerator_Regex_Parser($this->_regexLexer);
  198. }
  199. function doLongestMatch($rules, $statename, $ruleindex)
  200. {
  201. fwrite($this->out, '
  202. if (' . $this->counter . ' >= strlen(' . $this->input . ')) {
  203. return false; // end of input
  204. }
  205. do {
  206. $rules = array(');
  207. foreach ($rules as $rule) {
  208. fwrite($this->out, '
  209. \'/\G' . $rule['pattern'] . '/' . $this->patternFlags . ' \',');
  210. }
  211. fwrite($this->out, '
  212. );
  213. $match = false;
  214. foreach ($rules as $index => $rule) {
  215. if (preg_match($rule, substr(' . $this->input . ', ' .
  216. $this->counter . '), $yymatches)) {
  217. if ($match) {
  218. if (strlen($yymatches[0]) > strlen($match[0][0])) {
  219. $match = array($yymatches, $index); // matches, token
  220. }
  221. } else {
  222. $match = array($yymatches, $index);
  223. }
  224. }
  225. }
  226. if (!$match) {
  227. throw new Exception(\'Unexpected input at line \' . ' . $this->line . ' .
  228. \': \' . ' . $this->input . '[' . $this->counter . ']);
  229. }
  230. ' . $this->token . ' = $match[1];
  231. ' . $this->value . ' = $match[0][0];
  232. $yysubmatches = $match[0];
  233. array_shift($yysubmatches);
  234. if (!$yysubmatches) {
  235. $yysubmatches = array();
  236. }
  237. $r = $this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}($yysubmatches);
  238. if ($r === null) {
  239. ' . $this->counter . ' += strlen(' . $this->value . ');
  240. ' . $this->line . ' += substr_count(' . $this->value . ', "\n");
  241. // accept this token
  242. return true;
  243. } elseif ($r === true) {
  244. // we have changed state
  245. // process this token in the new state
  246. return $this->yylex();
  247. } elseif ($r === false) {
  248. ' . $this->counter . ' += strlen(' . $this->value . ');
  249. ' . $this->line . ' += substr_count(' . $this->value . ', "\n");
  250. if (' . $this->counter . ' >= strlen(' . $this->input . ')) {
  251. return false; // end of input
  252. }
  253. // skip this token
  254. continue;
  255. } else {');
  256. fwrite($this->out, '
  257. $yy_yymore_patterns = array_slice($rules, $this->token, true);
  258. // yymore is needed
  259. do {
  260. if (!isset($yy_yymore_patterns[' . $this->token . '])) {
  261. throw new Exception(\'cannot do yymore for the last token\');
  262. }
  263. $match = false;
  264. foreach ($yy_yymore_patterns[' . $this->token . '] as $index => $rule) {
  265. if (preg_match(\'/\' . $rule . \'/' . $this->patternFlags . '\',
  266. ' . $this->input . ', $yymatches, null, ' . $this->counter . ')) {
  267. $yymatches = array_filter($yymatches, \'strlen\'); // remove empty sub-patterns
  268. if ($match) {
  269. if (strlen($yymatches[0]) > strlen($match[0][0])) {
  270. $match = array($yymatches, $index); // matches, token
  271. }
  272. } else {
  273. $match = array($yymatches, $index);
  274. }
  275. }
  276. }
  277. if (!$match) {
  278. throw new Exception(\'Unexpected input at line \' . ' . $this->line . ' .
  279. \': \' . ' . $this->input . '[' . $this->counter . ']);
  280. }
  281. ' . $this->token . ' = $match[1];
  282. ' . $this->value . ' = $match[0][0];
  283. $yysubmatches = $match[0];
  284. array_shift($yysubmatches);
  285. if (!$yysubmatches) {
  286. $yysubmatches = array();
  287. }
  288. ' . $this->line . ' = substr_count(' . $this->value . ', "\n");
  289. $r = $this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}();
  290. } while ($r !== null || !$r);
  291. if ($r === true) {
  292. // we have changed state
  293. // process this token in the new state
  294. return $this->yylex();
  295. } else {
  296. // accept
  297. ' . $this->counter . ' += strlen(' . $this->value . ');
  298. ' . $this->line . ' += substr_count(' . $this->value . ', "\n");
  299. return true;
  300. }
  301. }
  302. } while (true);
  303. ');
  304. }
  305. function doFirstMatch($rules, $statename, $ruleindex)
  306. {
  307. $patterns = array();
  308. $pattern = '/';
  309. $ruleMap = array();
  310. $tokenindex = array();
  311. $actualindex = 1;
  312. $i = 0;
  313. foreach ($rules as $rule) {
  314. $ruleMap[$i++] = $actualindex;
  315. $tokenindex[$actualindex] = $rule['subpatterns'];
  316. $actualindex += $rule['subpatterns'] + 1;
  317. $patterns[] = '\G(' . $rule['pattern'] . ')';
  318. }
  319. // Re-index tokencount from zero.
  320. $tokencount = array_values($tokenindex);
  321. $tokenindex = var_export($tokenindex, true);
  322. $tokenindex = explode("\n", $tokenindex);
  323. // indent for prettiness
  324. $tokenindex = implode("\n ", $tokenindex);
  325. $pattern .= implode('|', $patterns);
  326. $pattern .= '/' . $this->patternFlags;
  327. fwrite($this->out, '
  328. $tokenMap = ' . $tokenindex . ';
  329. if (' . $this->counter . ' >= strlen(' . $this->input . ')) {
  330. return false; // end of input
  331. }
  332. ');
  333. fwrite($this->out, '$yy_global_pattern = \'' .
  334. $pattern . '\';' . "\n");
  335. fwrite($this->out, '
  336. do {
  337. if (preg_match($yy_global_pattern,' . $this->input . ', $yymatches, null, ' .
  338. $this->counter .
  339. ')) {
  340. $yysubmatches = $yymatches;
  341. $yymatches = array_filter($yymatches, \'strlen\'); // remove empty sub-patterns
  342. if (!count($yymatches)) {
  343. throw new Exception(\'Error: lexing failed because a rule matched\' .
  344. \' an empty string. Input "\' . substr(' . $this->input . ',
  345. ' . $this->counter . ', 5) . \'... state ' . $statename . '\');
  346. }
  347. next($yymatches); // skip global match
  348. ' . $this->token . ' = key($yymatches); // token number
  349. if ($tokenMap[' . $this->token . ']) {
  350. // extract sub-patterns for passing to lex function
  351. $yysubmatches = array_slice($yysubmatches, ' . $this->token . ' + 1,
  352. $tokenMap[' . $this->token . ']);
  353. } else {
  354. $yysubmatches = array();
  355. }
  356. ' . $this->value . ' = current($yymatches); // token value
  357. $r = $this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}($yysubmatches);
  358. if ($r === null) {
  359. ' . $this->counter . ' += strlen(' . $this->value . ');
  360. ' . $this->line . ' += substr_count(' . $this->value . ', "\n");
  361. // accept this token
  362. return true;
  363. } elseif ($r === true) {
  364. // we have changed state
  365. // process this token in the new state
  366. return $this->yylex();
  367. } elseif ($r === false) {
  368. ' . $this->counter . ' += strlen(' . $this->value . ');
  369. ' . $this->line . ' += substr_count(' . $this->value . ', "\n");
  370. if (' . $this->counter . ' >= strlen(' . $this->input . ')) {
  371. return false; // end of input
  372. }
  373. // skip this token
  374. continue;
  375. } else {');
  376. fwrite($this->out, '
  377. $yy_yymore_patterns = array(' . "\n");
  378. $extra = 0;
  379. for($i = 0; count($patterns); $i++) {
  380. unset($patterns[$i]);
  381. $extra += $tokencount[0];
  382. array_shift($tokencount);
  383. fwrite($this->out, ' ' . $ruleMap[$i] . ' => array(' . $extra . ', "' .
  384. implode('|', $patterns) . "\"),\n");
  385. }
  386. fwrite($this->out, ' );' . "\n");
  387. fwrite($this->out, '
  388. // yymore is needed
  389. do {
  390. if (!strlen($yy_yymore_patterns[' . $this->token . '][1])) {
  391. throw new Exception(\'cannot do yymore for the last token\');
  392. }
  393. $yysubmatches = array();
  394. if (preg_match(\'/\' . $yy_yymore_patterns[' . $this->token . '][1] . \'/' . $this->patternFlags . '\',
  395. ' . $this->input . ', $yymatches, null, ' . $this->counter .')) {
  396. $yysubmatches = $yymatches;
  397. $yymatches = array_filter($yymatches, \'strlen\'); // remove empty sub-patterns
  398. next($yymatches); // skip global match
  399. ' . $this->token . ' += key($yymatches) + $yy_yymore_patterns[' . $this->token . '][0]; // token number
  400. ' . $this->value . ' = current($yymatches); // token value
  401. ' . $this->line . ' = substr_count(' . $this->value . ', "\n");
  402. if ($tokenMap[' . $this->token . ']) {
  403. // extract sub-patterns for passing to lex function
  404. $yysubmatches = array_slice($yysubmatches, ' . $this->token . ' + 1,
  405. $tokenMap[' . $this->token . ']);
  406. } else {
  407. $yysubmatches = array();
  408. }
  409. }
  410. $r = $this->{\'yy_r' . $ruleindex . '_\' . ' . $this->token . '}($yysubmatches);
  411. } while ($r !== null && !is_bool($r));
  412. if ($r === true) {
  413. // we have changed state
  414. // process this token in the new state
  415. return $this->yylex();
  416. } elseif ($r === false) {
  417. ' . $this->counter . ' += strlen(' . $this->value . ');
  418. ' . $this->line . ' += substr_count(' . $this->value . ', "\n");
  419. if (' . $this->counter . ' >= strlen(' . $this->input . ')) {
  420. return false; // end of input
  421. }
  422. // skip this token
  423. continue;
  424. } else {
  425. // accept
  426. ' . $this->counter . ' += strlen(' . $this->value . ');
  427. ' . $this->line . ' += substr_count(' . $this->value . ', "\n");
  428. return true;
  429. }
  430. }
  431. } else {
  432. throw new Exception(\'Unexpected input at line\' . ' . $this->line . ' .
  433. \': \' . ' . $this->input . '[' . $this->counter . ']);
  434. }
  435. break;
  436. } while (true);
  437. ');
  438. }
  439. function makeCaseInsensitve($string)
  440. {
  441. return preg_replace('/[a-z]/ie', "'[\\0'.strtoupper('\\0').']'", strtolower($string));
  442. }
  443. function outputRules($rules, $statename)
  444. {
  445. if (!$statename) {
  446. $statename = $this -> _outRuleIndex;
  447. }
  448. fwrite($this->out, '
  449. function yylex' . $this -> _outRuleIndex . '()
  450. {');
  451. if ($this->matchlongest) {
  452. $ruleMap = array();
  453. foreach ($rules as $i => $rule) {
  454. $ruleMap[$i] = $i;
  455. }
  456. $this->doLongestMatch($rules, $statename, $this -> _outRuleIndex);
  457. } else {
  458. $ruleMap = array();
  459. $actualindex = 1;
  460. $i = 0;
  461. foreach ($rules as $rule) {
  462. $ruleMap[$i++] = $actualindex;
  463. $actualindex += $rule['subpatterns'] + 1;
  464. }
  465. $this->doFirstMatch($rules, $statename, $this -> _outRuleIndex);
  466. }
  467. fwrite($this->out, '
  468. } // end function
  469. ');
  470. if (is_string($statename)) {
  471. fwrite($this->out, '
  472. const ' . $statename . ' = ' . $this -> _outRuleIndex . ';
  473. ');
  474. }
  475. foreach ($rules as $i => $rule) {
  476. fwrite($this->out, ' function yy_r' . $this -> _outRuleIndex . '_' . $ruleMap[$i] . '($yy_subpatterns)
  477. {
  478. ' . $rule['code'] .
  479. ' }
  480. ');
  481. }
  482. $this -> _outRuleIndex++; // for next set of rules
  483. }
  484. function error($msg)
  485. {
  486. echo 'Error on line ' . $this->lex->line . ': ' , $msg;
  487. }
  488. function _validatePattern($pattern, $update = false)
  489. {
  490. $this->_regexLexer->reset($pattern, $this->lex->line);
  491. $this->_regexParser->reset($this->_patternIndex, $update);
  492. try {
  493. while ($this->_regexLexer->yylex()) {
  494. $this->_regexParser->doParse(
  495. $this->_regexLexer->token, $this->_regexLexer->value);
  496. }
  497. $this->_regexParser->doParse(0, 0);
  498. } catch (PHP_LexerGenerator_Exception $e) {
  499. $this->error($e->getMessage());
  500. throw new PHP_LexerGenerator_Exception('Invalid pattern "' . $pattern . '"');
  501. }
  502. return $this->_regexParser->result;
  503. }
  504. #line 529 "Parser.php"
  505. /* Next is all token values, as class constants
  506. */
  507. /*
  508. ** These constants (all generated automatically by the parser generator)
  509. ** specify the various kinds of tokens (terminals) that the parser
  510. ** understands.
  511. **
  512. ** Each symbol here is a terminal symbol in the grammar.
  513. */
  514. const PHPCODE = 1;
  515. const COMMENTSTART = 2;
  516. const COMMENTEND = 3;
  517. const PI = 4;
  518. const SUBPATTERN = 5;
  519. const CODE = 6;
  520. const PATTERN = 7;
  521. const QUOTE = 8;
  522. const SINGLEQUOTE = 9;
  523. const YY_NO_ACTION = 99;
  524. const YY_ACCEPT_ACTION = 98;
  525. const YY_ERROR_ACTION = 97;
  526. /* Next are that tables used to determine what action to take based on the
  527. ** current state and lookahead token. These tables are used to implement
  528. ** functions that take a state number and lookahead value and return an
  529. ** action integer.
  530. **
  531. ** Suppose the action integer is N. Then the action is determined as
  532. ** follows
  533. **
  534. ** 0 <= N < self::YYNSTATE Shift N. That is,
  535. ** push the lookahead
  536. ** token onto the stack
  537. ** and goto state N.
  538. **
  539. ** self::YYNSTATE <= N < self::YYNSTATE+self::YYNRULE Reduce by rule N-YYNSTATE.
  540. **
  541. ** N == self::YYNSTATE+self::YYNRULE A syntax error has occurred.
  542. **
  543. ** N == self::YYNSTATE+self::YYNRULE+1 The parser accepts its
  544. ** input. (and concludes parsing)
  545. **
  546. ** N == self::YYNSTATE+self::YYNRULE+2 No such action. Denotes unused
  547. ** slots in the yy_action[] table.
  548. **
  549. ** The action table is constructed as a single large static array $yy_action.
  550. ** Given state S and lookahead X, the action is computed as
  551. **
  552. ** self::$yy_action[self::$yy_shift_ofst[S] + X ]
  553. **
  554. ** If the index value self::$yy_shift_ofst[S]+X is out of range or if the value
  555. ** self::$yy_lookahead[self::$yy_shift_ofst[S]+X] is not equal to X or if
  556. ** self::$yy_shift_ofst[S] is equal to self::YY_SHIFT_USE_DFLT, it means that
  557. ** the action is not in the table and that self::$yy_default[S] should be used instead.
  558. **
  559. ** The formula above is for computing the action when the lookahead is
  560. ** a terminal symbol. If the lookahead is a non-terminal (as occurs after
  561. ** a reduce action) then the static $yy_reduce_ofst array is used in place of
  562. ** the static $yy_shift_ofst array and self::YY_REDUCE_USE_DFLT is used in place of
  563. ** self::YY_SHIFT_USE_DFLT.
  564. **
  565. ** The following are the tables generated in this section:
  566. **
  567. ** self::$yy_action A single table containing all actions.
  568. ** self::$yy_lookahead A table containing the lookahead for each entry in
  569. ** yy_action. Used to detect hash collisions.
  570. ** self::$yy_shift_ofst For each state, the offset into self::$yy_action for
  571. ** shifting terminals.
  572. ** self::$yy_reduce_ofst For each state, the offset into self::$yy_action for
  573. ** shifting non-terminals after a reduce.
  574. ** self::$yy_default Default action for each state.
  575. */
  576. const YY_SZ_ACTTAB = 91;
  577. static public $yy_action = array(
  578. /* 0 */ 25, 50, 49, 31, 49, 54, 53, 54, 53, 35,
  579. /* 10 */ 11, 49, 18, 22, 54, 53, 14, 59, 51, 28,
  580. /* 20 */ 55, 57, 58, 59, 47, 1, 55, 57, 32, 15,
  581. /* 30 */ 49, 29, 49, 54, 53, 54, 53, 30, 52, 49,
  582. /* 40 */ 42, 46, 54, 53, 98, 56, 5, 13, 38, 18,
  583. /* 50 */ 49, 43, 40, 54, 53, 12, 39, 18, 3, 37,
  584. /* 60 */ 36, 17, 7, 8, 2, 10, 33, 18, 9, 2,
  585. /* 70 */ 41, 44, 1, 24, 16, 34, 45, 27, 60, 48,
  586. /* 80 */ 4, 1, 2, 1, 20, 19, 21, 26, 23, 6,
  587. /* 90 */ 7,
  588. );
  589. static public $yy_lookahead = array(
  590. /* 0 */ 3, 1, 5, 4, 5, 8, 9, 8, 9, 3,
  591. /* 10 */ 19, 5, 21, 4, 8, 9, 7, 5, 6, 14,
  592. /* 20 */ 8, 9, 3, 5, 6, 20, 8, 9, 3, 7,
  593. /* 30 */ 5, 4, 5, 8, 9, 8, 9, 3, 1, 5,
  594. /* 40 */ 5, 6, 8, 9, 11, 12, 13, 19, 5, 21,
  595. /* 50 */ 5, 8, 9, 8, 9, 19, 5, 21, 5, 8,
  596. /* 60 */ 9, 1, 2, 1, 2, 19, 14, 21, 1, 2,
  597. /* 70 */ 5, 6, 20, 15, 16, 14, 2, 14, 1, 1,
  598. /* 80 */ 5, 20, 2, 20, 18, 21, 18, 17, 4, 13,
  599. /* 90 */ 2,
  600. );
  601. const YY_SHIFT_USE_DFLT = -4;
  602. const YY_SHIFT_MAX = 35;
  603. static public $yy_shift_ofst = array(
  604. /* 0 */ 60, 27, -1, 45, 45, 62, 67, 84, 80, 80,
  605. /* 10 */ 34, 25, -3, 6, 51, 51, 9, 88, 12, 18,
  606. /* 20 */ 43, 43, 65, 35, 19, 0, 22, 74, 74, 75,
  607. /* 30 */ 78, 53, 77, 74, 74, 37,
  608. );
  609. const YY_REDUCE_USE_DFLT = -10;
  610. const YY_REDUCE_MAX = 17;
  611. static public $yy_reduce_ofst = array(
  612. /* 0 */ 33, 28, -9, 46, 36, 52, 63, 58, 61, 5,
  613. /* 10 */ 64, 64, 64, 64, 66, 68, 70, 76,
  614. );
  615. static public $yyExpectedTokens = array(
  616. /* 0 */ array(1, 2, ),
  617. /* 1 */ array(4, 5, 8, 9, ),
  618. /* 2 */ array(4, 5, 8, 9, ),
  619. /* 3 */ array(5, 8, 9, ),
  620. /* 4 */ array(5, 8, 9, ),
  621. /* 5 */ array(1, 2, ),
  622. /* 6 */ array(1, 2, ),
  623. /* 7 */ array(4, ),
  624. /* 8 */ array(2, ),
  625. /* 9 */ array(2, ),
  626. /* 10 */ array(3, 5, 8, 9, ),
  627. /* 11 */ array(3, 5, 8, 9, ),
  628. /* 12 */ array(3, 5, 8, 9, ),
  629. /* 13 */ array(3, 5, 8, 9, ),
  630. /* 14 */ array(5, 8, 9, ),
  631. /* 15 */ array(5, 8, 9, ),
  632. /* 16 */ array(4, 7, ),
  633. /* 17 */ array(2, ),
  634. /* 18 */ array(5, 6, 8, 9, ),
  635. /* 19 */ array(5, 6, 8, 9, ),
  636. /* 20 */ array(5, 8, 9, ),
  637. /* 21 */ array(5, 8, 9, ),
  638. /* 22 */ array(5, 6, ),
  639. /* 23 */ array(5, 6, ),
  640. /* 24 */ array(3, ),
  641. /* 25 */ array(1, ),
  642. /* 26 */ array(7, ),
  643. /* 27 */ array(2, ),
  644. /* 28 */ array(2, ),
  645. /* 29 */ array(5, ),
  646. /* 30 */ array(1, ),
  647. /* 31 */ array(5, ),
  648. /* 32 */ array(1, ),
  649. /* 33 */ array(2, ),
  650. /* 34 */ array(2, ),
  651. /* 35 */ array(1, ),
  652. /* 36 */ array(),
  653. /* 37 */ array(),
  654. /* 38 */ array(),
  655. /* 39 */ array(),
  656. /* 40 */ array(),
  657. /* 41 */ array(),
  658. /* 42 */ array(),
  659. /* 43 */ array(),
  660. /* 44 */ array(),
  661. /* 45 */ array(),
  662. /* 46 */ array(),
  663. /* 47 */ array(),
  664. /* 48 */ array(),
  665. /* 49 */ array(),
  666. /* 50 */ array(),
  667. /* 51 */ array(),
  668. /* 52 */ array(),
  669. /* 53 */ array(),
  670. /* 54 */ array(),
  671. /* 55 */ array(),
  672. /* 56 */ array(),
  673. /* 57 */ array(),
  674. /* 58 */ array(),
  675. /* 59 */ array(),
  676. /* 60 */ array(),
  677. );
  678. static public $yy_default = array(
  679. /* 0 */ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
  680. /* 10 */ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
  681. /* 20 */ 72, 73, 97, 97, 97, 79, 67, 64, 65, 97,
  682. /* 30 */ 75, 97, 74, 62, 63, 78, 92, 91, 96, 93,
  683. /* 40 */ 95, 70, 68, 94, 71, 82, 69, 84, 77, 87,
  684. /* 50 */ 81, 83, 80, 86, 85, 88, 61, 89, 66, 90,
  685. /* 60 */ 76,
  686. );
  687. /* The next thing included is series of defines which control
  688. ** various aspects of the generated parser.
  689. ** self::YYNOCODE is a number which corresponds
  690. ** to no legal terminal or nonterminal number. This
  691. ** number is used to fill in empty slots of the hash
  692. ** table.
  693. ** self::YYFALLBACK If defined, this indicates that one or more tokens
  694. ** have fall-back values which should be used if the
  695. ** original value of the token will not parse.
  696. ** self::YYSTACKDEPTH is the maximum depth of the parser's stack.
  697. ** self::YYNSTATE the combined number of states.
  698. ** self::YYNRULE the number of rules in the grammar
  699. ** self::YYERRORSYMBOL is the code number of the error symbol. If not
  700. ** defined, then do no error processing.
  701. */
  702. const YYNOCODE = 23;
  703. const YYSTACKDEPTH = 100;
  704. const YYNSTATE = 61;
  705. const YYNRULE = 36;
  706. const YYERRORSYMBOL = 10;
  707. const YYERRSYMDT = 'yy0';
  708. const YYFALLBACK = 0;
  709. /** The next table maps tokens into fallback tokens. If a construct
  710. * like the following:
  711. *
  712. * %fallback ID X Y Z.
  713. *
  714. * appears in the grammer, then ID becomes a fallback token for X, Y,
  715. * and Z. Whenever one of the tokens X, Y, or Z is input to the parser
  716. * but it does not parse, the type of the token is changed to ID and
  717. * the parse is retried before an error is thrown.
  718. */
  719. static public $yyFallback = array(
  720. );
  721. /**
  722. * Turn parser tracing on by giving a stream to which to write the trace
  723. * and a prompt to preface each trace message. Tracing is turned off
  724. * by making either argument NULL
  725. *
  726. * Inputs:
  727. *
  728. * - A stream resource to which trace output should be written.
  729. * If NULL, then tracing is turned off.
  730. * - A prefix string written at the beginning of every
  731. * line of trace output. If NULL, then tracing is
  732. * turned off.
  733. *
  734. * Outputs:
  735. *
  736. * - None.
  737. * @param resource
  738. * @param string
  739. */
  740. static function Trace($TraceFILE, $zTracePrompt)
  741. {
  742. if (!$TraceFILE) {
  743. $zTracePrompt = 0;
  744. } elseif (!$zTracePrompt) {
  745. $TraceFILE = 0;
  746. }
  747. self::$yyTraceFILE = $TraceFILE;
  748. self::$yyTracePrompt = $zTracePrompt;
  749. }
  750. /**
  751. * Output debug information to output (php://output stream)
  752. */
  753. static function PrintTrace()
  754. {
  755. self::$yyTraceFILE = fopen('php://output', 'w');
  756. self::$yyTracePrompt = '';
  757. }
  758. /**
  759. * @var resource|0
  760. */
  761. static public $yyTraceFILE;
  762. /**
  763. * String to prepend to debug output
  764. * @var string|0
  765. */
  766. static public $yyTracePrompt;
  767. /**
  768. * @var int
  769. */
  770. public $yyidx; /* Index of top element in stack */
  771. /**
  772. * @var int
  773. */
  774. public $yyerrcnt; /* Shifts left before out of the error */
  775. /**
  776. * @var array
  777. */
  778. public $yystack = array(); /* The parser's stack */
  779. /**
  780. * For tracing shifts, the names of all terminals and nonterminals
  781. * are required. The following table supplies these names
  782. * @var array
  783. */
  784. static public $yyTokenName = array(
  785. '$', 'PHPCODE', 'COMMENTSTART', 'COMMENTEND',
  786. 'PI', 'SUBPATTERN', 'CODE', 'PATTERN',
  787. 'QUOTE', 'SINGLEQUOTE', 'error', 'start',
  788. 'lexfile', 'declare', 'rules', 'declarations',
  789. 'processing_instructions', 'pattern_declarations', 'subpattern', 'rule',
  790. 'reset_rules', 'rule_subpattern',
  791. );
  792. /**
  793. * For tracing reduce actions, the names of all rules are required.
  794. * @var array
  795. */
  796. static public $yyRuleName = array(
  797. /* 0 */ "start ::= lexfile",
  798. /* 1 */ "lexfile ::= declare rules",
  799. /* 2 */ "lexfile ::= declare PHPCODE rules",
  800. /* 3 */ "lexfile ::= PHPCODE declare rules",
  801. /* 4 */ "lexfile ::= PHPCODE declare PHPCODE rules",
  802. /* 5 */ "declare ::= COMMENTSTART declarations COMMENTEND",
  803. /* 6 */ "declarations ::= processing_instructions pattern_declarations",
  804. /* 7 */ "processing_instructions ::= PI SUBPATTERN",
  805. /* 8 */ "processing_instructions ::= PI CODE",
  806. /* 9 */ "processing_instructions ::= processing_instructions PI SUBPATTERN",
  807. /* 10 */ "processing_instructions ::= processing_instructions PI CODE",
  808. /* 11 */ "pattern_declarations ::= PATTERN subpattern",
  809. /* 12 */ "pattern_declarations ::= pattern_declarations PATTERN subpattern",
  810. /* 13 */ "rules ::= COMMENTSTART rule COMMENTEND",
  811. /* 14 */ "rules ::= COMMENTSTART PI SUBPATTERN rule COMMENTEND",
  812. /* 15 */ "rules ::= COMMENTSTART rule COMMENTEND PHPCODE",
  813. /* 16 */ "rules ::= COMMENTSTART PI SUBPATTERN rule COMMENTEND PHPCODE",
  814. /* 17 */ "rules ::= reset_rules rule COMMENTEND",
  815. /* 18 */ "rules ::= reset_rules PI SUBPATTERN rule COMMENTEND",
  816. /* 19 */ "rules ::= reset_rules rule COMMENTEND PHPCODE",
  817. /* 20 */ "rules ::= reset_rules PI SUBPATTERN rule COMMENTEND PHPCODE",
  818. /* 21 */ "reset_rules ::= rules COMMENTSTART",
  819. /* 22 */ "rule ::= rule_subpattern CODE",
  820. /* 23 */ "rule ::= rule rule_subpattern CODE",
  821. /* 24 */ "rule_subpattern ::= QUOTE",
  822. /* 25 */ "rule_subpattern ::= SINGLEQUOTE",
  823. /* 26 */ "rule_subpattern ::= SUBPATTERN",
  824. /* 27 */ "rule_subpattern ::= rule_subpattern QUOTE",
  825. /* 28 */ "rule_subpattern ::= rule_subpattern SINGLEQUOTE",
  826. /* 29 */ "rule_subpattern ::= rule_subpattern SUBPATTERN",
  827. /* 30 */ "subpattern ::= QUOTE",
  828. /* 31 */ "subpattern ::= SINGLEQUOTE",
  829. /* 32 */ "subpattern ::= SUBPATTERN",
  830. /* 33 */ "subpattern ::= subpattern QUOTE",
  831. /* 34 */ "subpattern ::= subpattern SINGLEQUOTE",
  832. /* 35 */ "subpattern ::= subpattern SUBPATTERN",
  833. );
  834. /**
  835. * This function returns the symbolic name associated with a token
  836. * value.
  837. * @param int
  838. * @return string
  839. */
  840. function tokenName($tokenType)
  841. {
  842. if ($tokenType === 0) {
  843. return 'End of Input';
  844. }
  845. if ($tokenType > 0 && $tokenType < count(self::$yyTokenName)) {
  846. return self::$yyTokenName[$tokenType];
  847. } else {
  848. return "Unknown";
  849. }
  850. }
  851. /**
  852. * The following function deletes the value associated with a
  853. * symbol. The symbol can be either a terminal or nonterminal.
  854. * @param int the symbol code
  855. * @param mixed the symbol's value
  856. */
  857. static function yy_destructor($yymajor, $yypminor)
  858. {
  859. switch ($yymajor) {
  860. /* Here is inserted the actions which take place when a
  861. ** terminal or non-terminal is destroyed. This can happen
  862. ** when the symbol is popped from the stack during a
  863. ** reduce or during error processing or when a parser is
  864. ** being destroyed before it is finished parsing.
  865. **
  866. ** Note: during a reduce, the only symbols destroyed are those
  867. ** which appear on the RHS of the rule, but which are not used
  868. ** inside the C code.
  869. */
  870. default: break; /* If no destructor action specified: do nothing */
  871. }
  872. }
  873. /**
  874. * Pop the parser's stack once.
  875. *
  876. * If there is a destructor routine associated with the token which
  877. * is popped from the stack, then call it.
  878. *
  879. * Return the major token number for the symbol popped.
  880. * @param PHP_LexerGenerator_ParseryyParser
  881. * @return int
  882. */
  883. function yy_pop_parser_stack()
  884. {
  885. if (!count($this->yystack)) {
  886. return;
  887. }
  888. $yytos = array_pop($this->yystack);
  889. if (self::$yyTraceFILE && $this->yyidx >= 0) {
  890. fwrite(self::$yyTraceFILE,
  891. self::$yyTracePrompt . 'Popping ' . self::$yyTokenName[$yytos->major] .
  892. "\n");
  893. }
  894. $yymajor = $yytos->major;
  895. self::yy_destructor($yymajor, $yytos->minor);
  896. $this->yyidx--;
  897. return $yymajor;
  898. }
  899. /**
  900. * Deallocate and destroy a parser. Destructors are all called for
  901. * all stack elements before shutting the parser down.
  902. */
  903. function __destruct()
  904. {
  905. while ($this->yyidx >= 0) {
  906. $this->yy_pop_parser_stack();
  907. }
  908. if (is_resource(self::$yyTraceFILE)) {
  909. fclose(self::$yyTraceFILE);
  910. }
  911. }
  912. /**
  913. * Based on the current state and parser stack, get a list of all
  914. * possible lookahead tokens
  915. * @param int
  916. * @return array
  917. */
  918. function yy_get_expected_tokens($token)
  919. {
  920. $state = $this->yystack[$this->yyidx]->stateno;
  921. $expected = self::$yyExpectedTokens[$state];
  922. if (in_array($token, self::$yyExpectedTokens[$state], true)) {
  923. return $expected;
  924. }
  925. $stack = $this->yystack;
  926. $yyidx = $this->yyidx;
  927. do {
  928. $yyact = $this->yy_find_shift_action($token);
  929. if ($yyact >= self::YYNSTATE && $yyact < self::YYNSTATE + self::YYNRULE) {
  930. // reduce action
  931. $done = 0;
  932. do {
  933. if ($done++ == 100) {
  934. $this->yyidx = $yyidx;
  935. $this->yystack = $stack;
  936. // too much recursion prevents proper detection
  937. // so give up
  938. return array_unique($expected);
  939. }
  940. $yyruleno = $yyact - self::YYNSTATE;
  941. $this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs'];
  942. $nextstate = $this->yy_find_reduce_action(
  943. $this->yystack[$this->yyidx]->stateno,
  944. self::$yyRuleInfo[$yyruleno]['lhs']);
  945. if (isset(self::$yyExpectedTokens[$nextstate])) {
  946. $expected += self::$yyExpectedTokens[$nextstate];
  947. if (in_array($token,
  948. self::$yyExpectedTokens[$nextstate], true)) {
  949. $this->yyidx = $yyidx;
  950. $this->yystack = $stack;
  951. return array_unique($expected);
  952. }
  953. }
  954. if ($nextstate < self::YYNSTATE) {
  955. // we need to shift a non-terminal
  956. $this->yyidx++;
  957. $x = new PHP_LexerGenerator_ParseryyStackEntry;
  958. $x->stateno = $nextstate;
  959. $x->major = self::$yyRuleInfo[$yyruleno]['lhs'];
  960. $this->yystack[$this->yyidx] = $x;
  961. continue 2;
  962. } elseif ($nextstate == self::YYNSTATE + self::YYNRULE + 1) {
  963. $this->yyidx = $yyidx;
  964. $this->yystack = $stack;
  965. // the last token was just ignored, we can't accept
  966. // by ignoring input, this is in essence ignoring a
  967. // syntax error!
  968. return array_unique($expected);
  969. } elseif ($nextstate === self::YY_NO_ACTION) {
  970. $this->yyidx = $yyidx;
  971. $this->yystack = $stack;
  972. // input accepted, but not shifted (I guess)
  973. return $expected;
  974. } else {
  975. $yyact = $nextstate;
  976. }
  977. } while (true);
  978. }
  979. break;
  980. } while (true);
  981. return array_unique($expected);
  982. }
  983. /**
  984. * Based on the parser state and current parser stack, determine whether
  985. * the lookahead token is possible.
  986. *
  987. * The parser will convert the token value to an error token if not. This
  988. * catches some unusual edge cases where the parser would fail.
  989. * @param int
  990. * @return bool
  991. */
  992. function yy_is_expected_token($token)
  993. {
  994. if ($token === 0) {
  995. return true; // 0 is not part of this
  996. }
  997. $state = $this->yystack[$this->yyidx]->stateno;
  998. if (in_array($token, self::$yyExpectedTokens[$state], true)) {
  999. return true;
  1000. }
  1001. $stack = $this->yystack;
  1002. $yyidx = $this->yyidx;
  1003. do {
  1004. $yyact = $this->yy_find_shift_action($token);
  1005. if ($yyact >= self::YYNSTATE && $yyact < self::YYNSTATE + self::YYNRULE) {
  1006. // reduce action
  1007. $done = 0;
  1008. do {
  1009. if ($done++ == 100) {
  1010. $this->yyidx = $yyidx;
  1011. $this->yystack = $stack;
  1012. // too much recursion prevents proper detection
  1013. // so give up
  1014. return true;
  1015. }
  1016. $yyruleno = $yyact - self::YYNSTATE;
  1017. $this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs'];
  1018. $nextstate = $this->yy_find_reduce_action(
  1019. $this->yystack[$this->yyidx]->stateno,
  1020. self::$yyRuleInfo[$yyruleno]['lhs']);
  1021. if (isset(self::$yyExpectedTokens[$nextstate]) &&
  1022. in_array($token, self::$yyExpectedTokens[$nextstate], true)) {
  1023. $this->yyidx = $yyidx;
  1024. $this->yystack = $stack;
  1025. return true;
  1026. }
  1027. if ($nextstate < self::YYNSTATE) {
  1028. // we need to shift a non-terminal
  1029. $this->yyidx++;
  1030. $x = new PHP_LexerGenerator_ParseryyStackEntry;
  1031. $x->stateno = $nextstate;
  1032. $x->major = self::$yyRuleInfo[$yyruleno]['lhs'];
  1033. $this->yystack[$this->yyidx] = $x;
  1034. continue 2;
  1035. } elseif ($nextstate == self::YYNSTATE + self::YYNRULE + 1) {
  1036. $this->yyidx = $yyidx;
  1037. $this->yystack = $stack;
  1038. if (!$token) {
  1039. // end of input: this is valid
  1040. return true;
  1041. }
  1042. // the last token was just ignored, we can't accept
  1043. // by ignoring input, this is in essence ignoring a
  1044. // syntax error!
  1045. return false;
  1046. } elseif ($nextstate === self::YY_NO_ACTION) {
  1047. $this->yyidx = $yyidx;
  1048. $this->yystack = $stack;
  1049. // input accepted, but not shifted (I guess)
  1050. return true;
  1051. } else {
  1052. $yyact = $nextstate;
  1053. }
  1054. } while (true);
  1055. }
  1056. break;
  1057. } while (true);
  1058. $this->yyidx = $yyidx;
  1059. $this->yystack = $stack;
  1060. return true;
  1061. }
  1062. /**
  1063. * Find the appropriate action for a parser given the terminal
  1064. * look-ahead token iLookAhead.
  1065. *
  1066. * If the look-ahead token is YYNOCODE, then check to see if the action is
  1067. * independent of the look-ahead. If it is, return the action, otherwise
  1068. * return YY_NO_ACTION.
  1069. * @param int The look-ahead token
  1070. */
  1071. function yy_find_shift_action($iLookAhead)
  1072. {
  1073. $stateno = $this->yystack[$this->yyidx]->stateno;
  1074. /* if ($this->yyidx < 0) return self::YY_NO_ACTION; */
  1075. if (!isset(self::$yy_shift_ofst[$stateno])) {
  1076. // no shift actions
  1077. return self::$yy_default[$stateno];
  1078. }
  1079. $i = self::$yy_shift_ofst[$stateno];
  1080. if ($i === self::YY_SHIFT_USE_DFLT) {
  1081. return self::$yy_default[$stateno];
  1082. }
  1083. if ($iLookAhead == self::YYNOCODE) {
  1084. return self::YY_NO_ACTION;
  1085. }
  1086. $i += $iLookAhead;
  1087. if ($i < 0 || $i >= self::YY_SZ_ACTTAB ||
  1088. self::$yy_lookahead[$i] != $iLookAhead) {
  1089. if (count(self::$yyFallback) && $iLookAhead < count(self::$yyFallback)
  1090. && ($iFallback = self::$yyFallback[$iLookAhead]) != 0) {
  1091. if (self::$yyTraceFILE) {
  1092. fwrite(self::$yyTraceFILE, self::$yyTracePrompt . "FALLBACK " .
  1093. self::$yyTokenName[$iLookAhead] . " => " .
  1094. self::$yyTokenName[$iFallback] . "\n");
  1095. }
  1096. return $this->yy_find_shift_action($iFallback);
  1097. }
  1098. return self::$yy_default[$stateno];
  1099. } else {
  1100. return self::$yy_action[$i];
  1101. }
  1102. }
  1103. /**
  1104. * Find the appropriate action for a parser given the non-terminal
  1105. * look-ahead token $iLookAhead.
  1106. *
  1107. * If the look-ahead token is self::YYNOCODE, then check to see if the action is
  1108. * independent of the look-ahead. If it is, return the action, otherwise
  1109. * return self::YY_NO_ACTION.
  1110. * @param int Current state number
  1111. * @param int The look-ahead token
  1112. */
  1113. function yy_find_reduce_action($stateno, $iLookAhead)
  1114. {
  1115. /* $stateno = $this->yystack[$this->yyidx]->stateno; */
  1116. if (!isset(self::$yy_reduce_ofst[$stateno])) {
  1117. return self::$yy_default[$stateno];
  1118. }
  1119. $i = self::$yy_reduce_ofst[$stateno];
  1120. if ($i == self::YY_REDUCE_USE_DFLT) {
  1121. return self::$yy_default[$stateno];
  1122. }
  1123. if ($iLookAhead == self::YYNOCODE) {
  1124. return self::YY_NO_ACTION;
  1125. }
  1126. $i += $iLookAhead;
  1127. if ($i < 0 || $i >= self::YY_SZ_ACTTAB ||
  1128. self::$yy_lookahead[$i] != $iLookAhead) {
  1129. return self::$yy_default[$stateno];
  1130. } else {
  1131. return self::$yy_action[$i];
  1132. }
  1133. }
  1134. /**
  1135. * Perform a shift action.
  1136. * @param int The new state to shift in
  1137. * @param int The major token to shift in
  1138. * @param mixed the minor token to shift in
  1139. */
  1140. function yy_shift($yyNewState, $yyMajor, $yypMinor)
  1141. {
  1142. $this->yyidx++;
  1143. if ($this->yyidx >= self::YYSTACKDEPTH) {
  1144. $this->yyidx--;
  1145. if (self::$yyTraceFILE) {
  1146. fprintf(self::$yyTraceFILE, "%sStack Overflow!\n", self::$yyTracePrompt);
  1147. }
  1148. while ($this->yyidx >= 0) {
  1149. $this->yy_pop_parser_stack();
  1150. }
  1151. /* Here code is inserted which will execute if the parser
  1152. ** stack ever overflows */
  1153. return;
  1154. }
  1155. $yytos = new PHP_LexerGenerator_ParseryyStackEntry;
  1156. $yytos->stateno = $yyNewState;
  1157. $yytos->major = $yyMajor;
  1158. $yytos->minor = $yypMinor;
  1159. array_push($this->yystack, $yytos);
  1160. if (self::$yyTraceFILE && $this->yyidx > 0) {
  1161. fprintf(self::$yyTraceFILE, "%sShift %d\n", self::$yyTracePrompt,
  1162. $yyNewState);
  1163. fprintf(self::$yyTraceFILE, "%sStack:", self::$yyTracePrompt);
  1164. for($i = 1; $i <= $this->yyidx; $i++) {
  1165. fprintf(self::$yyTraceFILE, " %s",
  1166. self::$yyTokenName[$this->yystack[$i]->major]);
  1167. }
  1168. fwrite(self::$yyTraceFILE,"\n");
  1169. }
  1170. }
  1171. /**
  1172. * The following table contains information about every rule that
  1173. * is used during the reduce.
  1174. *
  1175. * <pre>
  1176. * array(
  1177. * array(
  1178. * int $lhs; Symbol on the left-hand side of the rule
  1179. * int $nrhs; Number of right-hand side symbols in the rule
  1180. * ),...
  1181. * );
  1182. * </pre>
  1183. */
  1184. static public $yyRuleInfo = array(
  1185. array( 'lhs' => 11, 'rhs' => 1 ),
  1186. array( 'lhs' => 12, 'rhs' => 2 ),
  1187. array( 'lhs' => 12, 'rhs' => 3 ),
  1188. array( 'lhs' => 12, 'rhs' => 3 ),
  1189. array( 'lhs' => 12, 'rhs' => 4 ),
  1190. array( 'lhs' => 13, 'rhs' => 3 ),
  1191. array( 'lhs' => 15, 'rhs' => 2 ),
  1192. array( 'lhs' => 16, 'rhs' => 2 ),
  1193. array( 'lhs' => 16, 'rhs' => 2 ),
  1194. array( 'lhs' => 16, 'rhs' => 3 ),
  1195. array( 'lhs' => 16, 'rhs' => 3 ),
  1196. array( 'lhs' => 17, 'rhs' => 2 ),
  1197. array( 'lhs' => 17, 'rhs' => 3 ),
  1198. array( 'lhs' => 14, 'rhs' => 3 ),
  1199. array( 'lhs' => 14, 'rhs' => 5 ),
  1200. array( 'lhs' => 14, 'rhs' => 4 ),
  1201. array( 'lhs' => 14, 'rhs' => 6 ),
  1202. array( 'lhs' => 14, 'rhs' => 3 ),
  1203. array( 'lhs' => 14, 'rhs' => 5 ),
  1204. array( 'lhs' => 14, 'rhs' => 4 ),
  1205. array( 'lhs' => 14, 'rhs' => 6 ),
  1206. array( 'lhs' => 20, 'rhs' => 2 ),
  1207. array( 'lhs' => 19, 'rhs' => 2 ),
  1208. array( 'lhs' => 19, 'rhs' => 3 ),
  1209. array( 'lhs' => 21, 'rhs' => 1 ),
  1210. array( 'lhs' => 21, 'rhs' => 1 ),
  1211. array( 'lhs' => 21, 'rhs' => 1 ),
  1212. array( 'lhs' => 21, 'rhs' => 2 ),
  1213. array( 'lhs' => 21, 'rhs' => 2 ),
  1214. array( 'lhs' => 21, 'rhs' => 2 ),
  1215. array( 'lhs' => 18, 'rhs' => 1 ),
  1216. array( 'lhs' => 18, 'rhs' => 1 ),
  1217. array( 'lhs' => 18, 'rhs' => 1 ),
  1218. array( 'lhs' => 18, 'rhs' => 2 ),
  1219. array( 'lhs' => 18, 'rhs' => 2 ),
  1220. array( 'lhs' => 18, 'rhs' => 2 ),
  1221. );
  1222. /**
  1223. * The following table contains a mapping of reduce action to method name
  1224. * that handles the reduction.
  1225. *
  1226. * If a rule is not set, it has no handler.
  1227. */
  1228. static public $yyReduceMap = array(
  1229. 1 => 1,
  1230. 2 => 2,
  1231. 3 => 3,
  1232. 4 => 4,
  1233. 5 => 5,
  1234. 6 => 6,
  1235. 7 => 7,
  1236. 8 => 7,
  1237. 9 => 9,
  1238. 10 => 9,
  1239. 11 => 11,
  1240. 12 => 12,
  1241. 13 => 13,
  1242. 14 => 14,
  1243. 15 => 15,
  1244. 16 => 16,
  1245. 17 => 17,
  1246. 18 => 18,
  1247. 19 => 19,
  1248. 20 => 20,
  1249. 21 => 21,
  1250. 22 => 22,
  1251. 23 => 23,
  1252. 24 => 24,
  1253. 25 => 25,
  1254. 26 => 26,
  1255. 27 => 27,
  1256. 28 => 28,
  1257. 29 => 29,
  1258. 30 => 30,
  1259. 31 => 31,
  1260. 32 => 32,
  1261. 33 => 33,
  1262. 34 => 34,
  1263. 35 => 35,
  1264. );
  1265. /* Beginning here are the reduction cases. A typical example
  1266. ** follows:
  1267. ** #line <lineno> <grammarfile>
  1268. ** function yy_r0($yymsp){ ... } // User supplied code
  1269. ** #line <lineno> <thisfile>
  1270. */
  1271. #line 438 "Parser.y"
  1272. function yy_r1(){
  1273. fwrite($this->out, '
  1274. private $_yy_state = 1;
  1275. private $_yy_stack = array();
  1276. function yylex()
  1277. {
  1278. return $this->{\'yylex\' . $this->_yy_state}();
  1279. }
  1280. function yypushstate($state)
  1281. {
  1282. array_push($this->_yy_stack, $this->_yy_state);
  1283. $this->_yy_state = $state;
  1284. }
  1285. function yypopstate()
  1286. {
  1287. $this->_yy_state = array_pop($this->_yy_stack);
  1288. }
  1289. function yybegin($state)
  1290. {
  1291. $this->_yy_state = $state;
  1292. }
  1293. ');
  1294. foreach ($this->yystack[$this->yyidx + 0]->minor as $rule) {
  1295. $this->outputRules($rule['rules'], $rule['statename']);
  1296. if ($rule['code']) {
  1297. fwrite($this->out, $rule['code']);
  1298. }
  1299. }
  1300. }
  1301. #line 1352 "Parser.php"
  1302. #line 472 "Parser.y"
  1303. function yy_r2(){
  1304. fwrite($this->out, '
  1305. private $_yy_state = 1;
  1306. private $_yy_stack = array();
  1307. function yylex()
  1308. {
  1309. return $this->{\'yylex\' . $this->_yy_state}();
  1310. }
  1311. function yypushstate($state)
  1312. {
  1313. array_push($this->_yy_stack, $this->_yy_state);
  1314. $this->_yy_state = $state;
  1315. }
  1316. function yypopstate()
  1317. {
  1318. $this->_yy_state = array_pop($this->_yy_stack);
  1319. }
  1320. function yybegin($state)
  1321. {
  1322. $this->_yy_state = $state;
  1323. }
  1324. ');
  1325. if (strlen($this->yystack[$this->yyidx + -1]->minor)) {
  1326. fwrite($this->out, $this->yystack[$this->yyidx + -1]->minor);
  1327. }
  1328. foreach ($this->yystack[$this->yyidx + 0]->minor as $rule) {
  1329. $this->outputRules($rule['rules'], $rule['statename']);
  1330. if ($rule['code']) {
  1331. fwrite($this->out, $rule['code']);
  1332. }
  1333. }
  1334. }
  1335. #line 1391 "Parser.php"
  1336. #line 509 "Parser.y"
  1337. function yy_r3(){
  1338. if (strlen($this->yystack[$this->yyidx + -2]->minor)) {
  1339. fwrite($this->out, $this->yystack[$this->yyidx + -2]->minor);
  1340. }
  1341. fwrite($this->out, '
  1342. private $_yy_state = 1;
  1343. private $_yy_stack = array();
  1344. function yylex()
  1345. {
  1346. return $this->{\'yylex\' . $this->_yy_state}();
  1347. }
  1348. function yypushstate($state)
  1349. {
  1350. array_push($this->_yy_stack, $this->_yy_state);
  1351. $this->_yy_state = $state;
  1352. }
  1353. function yypopstate()
  1354. {
  1355. $this->_yy_state = array_pop($this->_yy_stack);
  1356. }
  1357. function yybegin($state)
  1358. {
  1359. $this->_yy_state = $state;
  1360. }
  1361. ');
  1362. foreach ($this->yystack[$this->yyidx + 0]->minor as $rule) {
  1363. $this->outputRules($rule['rules'], $rule['statename']);
  1364. if ($rule['code']) {
  1365. fwrite($this->out, $rule['code']);
  1366. }
  1367. }
  1368. }
  1369. #line 1430 "Parser.php"
  1370. #line 546 "Parser.y"
  1371. function yy_r4(){
  1372. if (strlen($this->yystack[$this->yyidx + -3]->minor)) {
  1373. fwrite($this->out, $this->yystack[$this->yyidx + -3]->minor);
  1374. }
  1375. fwrite($this->out, '
  1376. private $_yy_state = 1;
  1377. private $_yy_stack = array();
  1378. function yylex()
  1379. {
  1380. return $this->{\'yylex\' . $this->_yy_state}();
  1381. }
  1382. function yypushstate($state)
  1383. {
  1384. array_push($this->_yy_stack, $this->_yy_state);
  1385. $this->_yy_state = $state;
  1386. }
  1387. function yypopstate()
  1388. {
  1389. $this->_yy_state = array_pop($this->_yy_stack);
  1390. }
  1391. function yybegin($state)
  1392. {
  1393. $this->_yy_state = $state;
  1394. }
  1395. ');
  1396. if (strlen($this->yystack[$this->yyidx + -1]->minor)) {
  1397. fwrite($this->out, $this->yystack[$this->yyidx + -1]->minor);
  1398. }
  1399. foreach ($this->yystack[$this->yyidx + 0]->minor as $rule) {
  1400. $this->outputRules($rule['rules'], $rule['statename']);
  1401. if ($rule['code']) {
  1402. fwrite($this->out, $rule['code']);
  1403. }
  1404. }
  1405. }
  1406. #line 1472 "Parser.php"
  1407. #line 587 "Parser.y"
  1408. function yy_r5(){
  1409. $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor;
  1410. $this->patterns = $this->yystack[$this->yyidx + -1]->minor['patterns'];
  1411. $this->_patternIndex = 1;
  1412. }
  1413. #line 1479 "Parser.php"
  1414. #line 593 "Parser.y"
  1415. function yy_r6(){
  1416. $expected = array(
  1417. 'counter' => true,
  1418. 'input' => true,
  1419. 'token' => true,
  1420. 'value' => true,
  1421. 'line' => true,
  1422. );
  1423. foreach ($this->yystack[$this->yyidx + -1]->minor as $pi) {
  1424. if (isset($expected[$pi['pi']])) {
  1425. unset($expected[$pi['pi']]);
  1426. continue;
  1427. }
  1428. if (count($expected)) {
  1429. throw new Exception('Processing Instructions "' .
  1430. implode(', ', array_keys($expected)) . '" must be defined');
  1431. }
  1432. }
  1433. $expected = array(
  1434. 'caseinsensitive' => true,
  1435. 'counter' => true,
  1436. 'input' => true,
  1437. 'token' => true,
  1438. 'value' => true,
  1439. 'line' => true,
  1440. 'matchlongest' => true,
  1441. 'unicode' => true,
  1442. );
  1443. foreach ($this->yystack[$this->yyidx + -1]->minor as $pi) {
  1444. if (isset($expected[$pi['pi']])) {
  1445. $this->{$pi['pi']} = $pi['definition'];
  1446. if ($pi['pi'] == 'matchlongest') {
  1447. $this->matchlongest = true;
  1448. }
  1449. continue;
  1450. }
  1451. $this->error('Unknown processing instruction %' . $pi['pi'] .
  1452. ', should be one of "' . implode(', ', array_keys($expected)) . '"');
  1453. }
  1454. $this->patternFlags = ($this->caseinsensitive ? 'i' : '')
  1455. . ($this->unicode ? 'u' : '');
  1456. $this->_retvalue = array('patterns' => $this->yystack[$this->yyidx + 0]->minor, 'pis' => $this->yystack[$this->yyidx + -1]->minor);
  1457. $this->_patternIndex = 1;
  1458. }
  1459. #line 1525 "Parser.php"
  1460. #line 638 "Parser.y"
  1461. function yy_r7(){
  1462. $this->_retvalue = array(array('pi' => $this->yystack[$this->yyidx + -1]->minor, 'definition' => $this->yystack[$this->yyidx + 0]->minor));
  1463. }
  1464. #line 1530 "Parser.php"
  1465. #line 644 "Parser.y"
  1466. function yy_r9(){
  1467. $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor;
  1468. $this->_retvalue[] = array('pi' => $this->yystack[$this->yyidx + -1]->minor, 'definition' => $this->yystack[$this->yyidx + 0]->minor);
  1469. }
  1470. #line 1536 "Parser.php"
  1471. #line 653 "Parser.y"
  1472. function yy_r11(){
  1473. $this->_retvalue = array($this->yystack[$this->yyidx + -1]->minor => $this->yystack[$this->yyidx + 0]->minor);
  1474. // reset internal indicator of where we are in a pattern
  1475. $this->_patternIndex = 0;
  1476. }
  1477. #line 1543 "Parser.php"
  1478. #line 658 "Parser.y"
  1479. function yy_r12(){
  1480. $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor;
  1481. if (isset($this->_retvalue[$this->yystack[$this->yyidx + -1]->minor])) {
  1482. throw new Exception('Pattern "' . $this->yystack[$this->yyidx + -1]->minor . '" is already defined as "' .
  1483. $this->_retvalue[$this->yystack[$this->yyidx + -1]->minor] . '", cannot redefine as "' . $this->yystack[$this->yyidx + 0]->minor->string . '"');
  1484. }
  1485. $this->_retvalue[$this->yystack[$this->yyidx + -1]->minor] = $this->yystack[$this->yyidx + 0]->minor;
  1486. // reset internal indicator of where we are in a pattern declaration
  1487. $this->_patternIndex = 0;
  1488. }
  1489. #line 1555 "Parser.php"
  1490. #line 669 "Parser.y"
  1491. function yy_r13(){
  1492. $this->_retvalue = array(array('rules' => $this->yystack[$this->yyidx + -1]->minor, 'code' => '', 'statename' => ''));
  1493. }
  1494. #line 1560 "Parser.php"
  1495. #line 672 "Parser.y"
  1496. function yy_r14(){
  1497. if ($this->yystack[$this->yyidx + -3]->minor != 'statename') {
  1498. throw new Exception('Error: only %statename processing instruction ' .
  1499. 'is allowed in rule sections (found ' . $this->yystack[$this->yyidx + -3]->minor . ').');
  1500. }
  1501. $this->_retvalue = array(array('rules' => $this->yystack[$this->yyidx + -1]->minor, 'code' => '', 'statename' => $this->yystack[$this->yyidx + -2]->minor));
  1502. }
  1503. #line 1569 "Parser.php"
  1504. #line 679 "Parser.y"
  1505. function yy_r15(){
  1506. $this->_retvalue = array(array('rules' => $this->yystack[$this->yyidx + -2]->minor, 'code' => $this->yystack[$this->yyidx + 0]->minor, 'statename' => ''));
  1507. }
  1508. #line 1574 "Parser.php"
  1509. #line 682 "Parser.y"
  1510. function yy_r16(){
  1511. if ($this->yystack[$this->yyidx + -4]->minor != 'statename') {
  1512. throw new Exception('Error: only %statename processing instruction ' .
  1513. 'is allowed in rule sections (found ' . $this->yystack[$this->yyidx + -4]->minor . ').');
  1514. }
  1515. $this->_retvalue = array(array('rules' => $this->yystack[$this->yyidx + -2]->minor, 'code' => $this->yystack[$this->yyidx + 0]->minor, 'statename' => $this->yystack[$this->yyidx + -3]->minor));
  1516. $this->_patternIndex = 1;
  1517. }
  1518. #line 1584 "Parser.php"
  1519. #line 690 "Parser.y"
  1520. function yy_r17(){
  1521. $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor;
  1522. $this->_retvalue[] = array('rules' => $this->yystack[$this->yyidx + -1]->minor, 'code' => '', 'statename' => '');
  1523. $this->_patternIndex = 1;
  1524. }
  1525. #line 1591 "Parser.php"
  1526. #line 695 "Parser.y"
  1527. function yy_r18(){
  1528. if ($this->yystack[$this->yyidx + -3]->minor != 'statename') {
  1529. throw new Exception('Error: only %statename processing instruction ' .
  1530. 'is allowed in rule sections (found ' . $this->yystack[$this->yyidx + -3]->minor . ').');
  1531. }
  1532. $this->_retvalue = $this->yystack[$this->yyidx + -4]->minor;
  1533. $this->_retvalue[] = array('rules' => $this->yystack[$this->yyidx + -1]->minor, 'code' => '', 'statename' => $this->yystack[$this->yyidx + -2]->minor);
  1534. }
  1535. #line 1601 "Parser.php"
  1536. #line 703 "Parser.y"
  1537. function yy_r19(){
  1538. $this->_retvalue = $this->yystack[$this->yyidx + -3]->minor;
  1539. $this->_retvalue[] = array('rules' => $this->yystack[$this->yyidx + -2]->minor, 'code' => $this->yystack[$this->yyidx + 0]->minor, 'statename' => '');
  1540. }
  1541. #line 1607 "Parser.php"
  1542. #line 707 "Parser.y"
  1543. function yy_r20(){
  1544. if ($this->yystack[$this->yyidx + -4]->minor != 'statename') {
  1545. throw new Exception('Error: only %statename processing instruction ' .
  1546. 'is allowed in rule sections (found ' . $this->yystack[$this->yyidx + -4]->minor . ').');
  1547. }
  1548. $this->_retvalue = $this->yystack[$this->yyidx + -5]->minor;
  1549. $this->_retvalue[] = array('rules' => $this->yystack[$this->yyidx + -2]->minor, 'code' => $this->yystack[$this->yyidx + 0]->minor, 'statename' => $this->yystack[$this->yyidx + -3]->minor);
  1550. }
  1551. #line 1617 "Parser.php"
  1552. #line 716 "Parser.y"
  1553. function yy_r21(){
  1554. $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor;
  1555. $this->_patternIndex = 1;
  1556. }
  1557. #line 1623 "Parser.php"
  1558. #line 721 "Parser.y"
  1559. function yy_r22(){
  1560. $name = $this->yystack[$this->yyidx + -1]->minor[1];
  1561. $this->yystack[$this->yyidx + -1]->minor = $this->yystack[$this->yyidx + -1]->minor[0];
  1562. $this->yystack[$this->yyidx + -1]->minor = $this->_validatePattern($this->yystack[$this->yyidx + -1]->minor);
  1563. $this->_patternIndex += $this->yystack[$this->yyidx + -1]->minor['subpatterns'] + 1;
  1564. if (@preg_match('/' . str_replace('/', '\\/', $this->yystack[$this->yyidx + -1]->minor['pattern']) . '/', '')) {
  1565. $this->error('Rule "' . $name . '" can match the empty string, this will break lexing');
  1566. }
  1567. $this->_retvalue = array(array('pattern' => str_replace('/', '\\/', $this->yystack[$this->yyidx + -1]->minor->string), 'code' => $this->yystack[$this->yyidx + 0]->minor, 'subpatterns' => $this->yystack[$this->yyidx + -1]->minor['subpatterns']));
  1568. }
  1569. #line 1635 "Parser.php"
  1570. #line 731 "Parser.y"
  1571. function yy_r23(){
  1572. $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor;
  1573. $name = $this->yystack[$this->yyidx + -1]->minor[1];
  1574. $this->yystack[$this->yyidx + -1]->minor = $this->yystack[$this->yyidx + -1]->minor[0];
  1575. $this->yystack[$this->yyidx + -1]->minor = $this->_validatePattern($this->yystack[$this->yyidx + -1]->minor);
  1576. $this->_patternIndex += $this->yystack[$this->yyidx + -1]->minor['subpatterns'] + 1;
  1577. if (@preg_match('/' . str_replace('/', '\\/', $this->yystack[$this->yyidx + -1]->minor['pattern']) . '/', '')) {
  1578. $this->error('Rule "' . $name . '" can match the empty string, this will break lexing');
  1579. }
  1580. $this->_retvalue[] = array('pattern' => str_replace('/', '\\/', $this->yystack[$this->yyidx + -1]->minor->string), 'code' => $this->yystack[$this->yyidx + 0]->minor, 'subpatterns' => $this->yystack[$this->yyidx + -1]->minor['subpatterns']);
  1581. }
  1582. #line 1648 "Parser.php"
  1583. #line 743 "Parser.y"
  1584. function yy_r24(){
  1585. $this->_retvalue = array(preg_quote($this->yystack[$this->yyidx + 0]->minor, '/'), $this->yystack[$this->yyidx + 0]->minor);
  1586. }
  1587. #line 1653 "Parser.php"
  1588. #line 746 "Parser.y"
  1589. function yy_r25(){
  1590. $this->_retvalue = array($this->makeCaseInsensitve(preg_quote($this->yystack[$this->yyidx + 0]->minor, '/')), $this->yystack[$this->yyidx + 0]->minor);
  1591. }
  1592. #line 1658 "Parser.php"
  1593. #line 749 "Parser.y"
  1594. function yy_r26(){
  1595. if (!isset($this->patterns[$this->yystack[$this->yyidx + 0]->minor])) {
  1596. $this->error('Undefined pattern "' . $this->yystack[$this->yyidx + 0]->minor . '" used in rules');
  1597. throw new Exception('Undefined pattern "' . $this->yystack[$this->yyidx + 0]->minor . '" used in rules');
  1598. }
  1599. $this->_retvalue = array($this->patterns[$this->yystack[$this->yyidx + 0]->minor], $this->yystack[$this->yyidx + 0]->minor);
  1600. }
  1601. #line 1667 "Parser.php"
  1602. #line 756 "Parser.y"
  1603. function yy_r27(){
  1604. $this->_retvalue = array($this->yystack[$this->yyidx + -1]->minor[0] . preg_quote($this->yystack[$this->yyidx + 0]->minor, '/'), $this->yystack[$this->yyidx + -1]->minor[1] . ' ' . $this->yystack[$this->yyidx + 0]->minor);
  1605. }
  1606. #line 1672 "Parser.php"
  1607. #line 759 "Parser.y"
  1608. function yy_r28(){
  1609. $this->_retvalue = array($this->yystack[$this->yyidx + -1]->minor[0] . $this->makeCaseInsensitve(preg_quote($this->yystack[$this->yyidx + 0]->minor, '/')), $this->yystack[$this->yyidx + -1]->minor[1] . ' ' . $this->yystack[$this->yyidx + 0]->minor);
  1610. }
  1611. #line 1677 "Parser.php"
  1612. #line 762 "Parser.y"
  1613. function yy_r29(){
  1614. if (!isset($this->patterns[$this->yystack[$this->yyidx + 0]->minor])) {
  1615. $this->error('Undefined pattern "' . $this->yystack[$this->yyidx + 0]->minor . '" used in rules');
  1616. throw new Exception('Undefined pattern "' . $this->yystack[$this->yyidx + 0]->minor . '" used in rules');
  1617. }
  1618. $this->_retvalue = array($this->yystack[$this->yyidx + -1]->minor[0] . $this->patterns[$this->yystack[$this->yyidx + 0]->minor], $this->yystack[$this->yyidx + -1]->minor[1] . ' ' . $this->yystack[$this->yyidx + 0]->minor);
  1619. }
  1620. #line 1686 "Parser.php"
  1621. #line 770 "Parser.y"
  1622. function yy_r30(){
  1623. $this->_retvalue = preg_quote($this->yystack[$this->yyidx + 0]->minor, '/');
  1624. }
  1625. #line 1691 "Parser.php"
  1626. #line 773 "Parser.y"
  1627. function yy_r31(){
  1628. $this->_retvalue = $this->makeCaseInsensitve(preg_quote($this->yystack[$this->yyidx + 0]->minor, '/'));
  1629. }
  1630. #line 1696 "Parser.php"
  1631. #line 776 "Parser.y"
  1632. function yy_r32(){
  1633. // increment internal sub-pattern counter
  1634. // adjust back-references in pattern based on previous pattern
  1635. $test = $this->_validatePattern($this->yystack[$this->yyidx + 0]->minor, true);
  1636. $this->_patternIndex += $test['subpatterns'];
  1637. $this->_retvalue = $test['pattern'];
  1638. }
  1639. #line 1705 "Parser.php"
  1640. #line 783 "Parser.y"
  1641. function yy_r33(){
  1642. $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor . preg_quote($this->yystack[$this->yyidx + 0]->minor, '/');
  1643. }
  1644. #line 1710 "Parser.php"
  1645. #line 786 "Parser.y"
  1646. function yy_r34(){
  1647. $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor . $this->makeCaseInsensitve(preg_quote($this->yystack[$this->yyidx + 0]->minor, '/'));
  1648. }
  1649. #line 1715 "Parser.php"
  1650. #line 789 "Parser.y"
  1651. function yy_r35(){
  1652. // increment internal sub-pattern counter
  1653. // adjust back-references in pattern based on previous pattern
  1654. $test = $this->_validatePattern($this->yystack[$this->yyidx + 0]->minor, true);
  1655. $this->_patternIndex += $test['subpatterns'];
  1656. $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor . $test['pattern'];
  1657. }
  1658. #line 1724 "Parser.php"
  1659. /**
  1660. * placeholder for the left hand side in a reduce operation.
  1661. *
  1662. * For a parser with a rule like this:
  1663. * <pre>
  1664. * rule(A) ::= B. { A = 1; }
  1665. * </pre>
  1666. *
  1667. * The parser will translate to something like:
  1668. *
  1669. * <code>
  1670. * function yy_r0(){$this->_retvalue = 1;}
  1671. * </code>
  1672. */
  1673. private $_retvalue;
  1674. /**
  1675. * Perform a reduce action and the shift that must immediately
  1676. * follow the reduce.
  1677. *
  1678. * For a rule such as:
  1679. *
  1680. * <pre>
  1681. * A ::= B blah C. { dosomething(); }
  1682. * </pre>
  1683. *
  1684. * This function will first call the action, if any, ("dosomething();" in our
  1685. * example), and then it will pop three states from the stack,
  1686. * one for each entry on the right-hand side of the expression
  1687. * (B, blah, and C in our example rule), and then push the result of the action
  1688. * back on to the stack with the resulting state reduced to (as described in the .out
  1689. * file)
  1690. * @param int Number of the rule by which to reduce
  1691. */
  1692. function yy_reduce($yyruleno)
  1693. {
  1694. //int $yygoto; /* The next state */
  1695. //int $yyact; /* The next action */
  1696. //mixed $yygotominor; /* The LHS of the rule reduced */
  1697. //PHP_LexerGenerator_ParseryyStackEntry $yymsp; /* The top of the parser's stack */
  1698. //int $yysize; /* Amount to pop the stack */
  1699. $yymsp = $this->yystack[$this->yyidx];
  1700. if (self::$yyTraceFILE && $yyruleno >= 0
  1701. && $yyruleno < count(self::$yyRuleName)) {
  1702. fprintf(self::$yyTraceFILE, "%sReduce (%d) [%s].\n",
  1703. self::$yyTracePrompt, $yyruleno,
  1704. self::$yyRuleName[$yyruleno]);
  1705. }
  1706. $this->_retvalue = $yy_lefthand_side = null;
  1707. if (array_key_exists($yyruleno, self::$yyReduceMap)) {
  1708. // call the action
  1709. $this->_retvalue = null;
  1710. $this->{'yy_r' . self::$yyReduceMap[$yyruleno]}();
  1711. $yy_lefthand_side = $this->_retvalue;
  1712. }
  1713. $yygoto = self::$yyRuleInfo[$yyruleno]['lhs'];
  1714. $yysize = self::$yyRuleInfo[$yyruleno]['rhs'];
  1715. $this->yyidx -= $yysize;
  1716. for($i = $yysize; $i; $i--) {
  1717. // pop all of the right-hand side parameters
  1718. array_pop($this->yystack);
  1719. }
  1720. $yyact = $this->yy_find_reduce_action($this->yystack[$this->yyidx]->stateno, $yygoto);
  1721. if ($yyact < self::YYNSTATE) {
  1722. /* If we are not debugging and the reduce action popped at least
  1723. ** one element off the stack, then we can push the new element back
  1724. ** onto the stack here, and skip the stack overflow test in yy_shift().
  1725. ** That gives a significant speed improvement. */
  1726. if (!self::$yyTraceFILE && $yysize) {
  1727. $this->yyidx++;
  1728. $x = new PHP_LexerGenerator_ParseryyStackEntry;
  1729. $x->stateno = $yyact;
  1730. $x->major = $yygoto;
  1731. $x->minor = $yy_lefthand_side;
  1732. $this->yystack[$this->yyidx] = $x;
  1733. } else {
  1734. $this->yy_shift($yyact, $yygoto, $yy_lefthand_side);
  1735. }
  1736. } elseif ($yyact == self::YYNSTATE + self::YYNRULE + 1) {
  1737. $this->yy_accept();
  1738. }
  1739. }
  1740. /**
  1741. * The following code executes when the parse fails
  1742. *
  1743. * Code from %parse_fail is inserted here
  1744. */
  1745. function yy_parse_failed()
  1746. {
  1747. if (self::$yyTraceFILE) {
  1748. fprintf(self::$yyTraceFILE, "%sFail!\n", self::$yyTracePrompt);
  1749. }
  1750. while ($this->yyidx >= 0) {
  1751. $this->yy_pop_parser_stack();
  1752. }
  1753. /* Here code is inserted which will be executed whenever the
  1754. ** parser fails */
  1755. }
  1756. /**
  1757. * The following code executes when a syntax error first occurs.
  1758. *
  1759. * %syntax_error code is inserted here
  1760. * @param int The major type of the error token
  1761. * @param mixed The minor type of the error token
  1762. */
  1763. function yy_syntax_error($yymajor, $TOKEN)
  1764. {
  1765. #line 70 "Parser.y"
  1766. echo "Syntax Error on line " . $this->lex->line . ": token '" .
  1767. $this->lex->value . "' while parsing rule:";
  1768. foreach ($this->yystack as $entry) {
  1769. echo $this->tokenName($entry->major) . ' ';
  1770. }
  1771. foreach ($this->yy_get_expected_tokens($yymajor) as $token) {
  1772. $expect[] = self::$yyTokenName[$token];
  1773. }
  1774. throw new Exception('Unexpected ' . $this->tokenName($yymajor) . '(' . $TOKEN
  1775. . '), expected one of: ' . implode(',', $expect));
  1776. #line 1849 "Parser.php"
  1777. }
  1778. /**
  1779. * The following is executed when the parser accepts
  1780. *
  1781. * %parse_accept code is inserted here
  1782. */
  1783. function yy_accept()
  1784. {
  1785. if (self::$yyTraceFILE) {
  1786. fprintf(self::$yyTraceFILE, "%sAccept!\n", self::$yyTracePrompt);
  1787. }
  1788. while ($this->yyidx >= 0) {
  1789. $stack = $this->yy_pop_parser_stack();
  1790. }
  1791. /* Here code is inserted which will be executed whenever the
  1792. ** parser accepts */
  1793. }
  1794. /**
  1795. * The main parser program.
  1796. *
  1797. * The first argument is the major token number. The second is
  1798. * the token value string as scanned from the input.
  1799. *
  1800. * @param int the token number
  1801. * @param mixed the token value
  1802. * @param mixed any extra arguments that should be passed to handlers
  1803. */
  1804. function doParse($yymajor, $yytokenvalue)
  1805. {
  1806. // $yyact; /* The parser action. */
  1807. // $yyendofinput; /* True if we are at the end of input */
  1808. $yyerrorhit = 0; /* True if yymajor has invoked an error */
  1809. /* (re)initialize the parser, if necessary */
  1810. if ($this->yyidx === null || $this->yyidx < 0) {
  1811. /* if ($yymajor == 0) return; // not sure why this was here... */
  1812. $this->yyidx = 0;
  1813. $this->yyerrcnt = -1;
  1814. $x = new PHP_LexerGenerator_ParseryyStackEntry;
  1815. $x->stateno = 0;
  1816. $x->major = 0;
  1817. $this->yystack = array();
  1818. array_push($this->yystack, $x);
  1819. }
  1820. $yyendofinput = ($yymajor==0);
  1821. if (self::$yyTraceFILE) {
  1822. fprintf(self::$yyTraceFILE, "%sInput %s\n",
  1823. self::$yyTracePrompt, self::$yyTokenName[$yymajor]);
  1824. }
  1825. do {
  1826. $yyact = $this->yy_find_shift_action($yymajor);
  1827. if ($yymajor < self::YYERRORSYMBOL &&
  1828. !$this->yy_is_expected_token($yymajor)) {
  1829. // force a syntax error
  1830. $yyact = self::YY_ERROR_ACTION;
  1831. }
  1832. if ($yyact < self::YYNSTATE) {
  1833. $this->yy_shift($yyact, $yymajor, $yytokenvalue);
  1834. $this->yyerrcnt--;
  1835. if ($yyendofinput && $this->yyidx >= 0) {
  1836. $yymajor = 0;
  1837. } else {
  1838. $yymajor = self::YYNOCODE;
  1839. }
  1840. } elseif ($yyact < self::YYNSTATE + self::YYNRULE) {
  1841. $this->yy_reduce($yyact - self::YYNSTATE);
  1842. } elseif ($yyact == self::YY_ERROR_ACTION) {
  1843. if (self::$yyTraceFILE) {
  1844. fprintf(self::$yyTraceFILE, "%sSyntax Error!\n",
  1845. self::$yyTracePrompt);
  1846. }
  1847. if (self::YYERRORSYMBOL) {
  1848. /* A syntax error has occurred.
  1849. ** The response to an error depends upon whether or not the
  1850. ** grammar defines an error token "ERROR".
  1851. **
  1852. ** This is what we do if the grammar does define ERROR:
  1853. **
  1854. ** * Call the %syntax_error function.
  1855. **
  1856. ** * Begin popping the stack until we enter a state where
  1857. ** it is legal to shift the error symbol, then shift
  1858. ** the error symbol.
  1859. **
  1860. ** * Set the error count to three.
  1861. **
  1862. ** * Begin accepting and shifting new tokens. No new error
  1863. ** processing will occur until three tokens have been
  1864. ** shifted successfully.
  1865. **
  1866. */
  1867. if ($this->yyerrcnt < 0) {
  1868. $this->yy_syntax_error($yymajor, $yytokenvalue);
  1869. }
  1870. $yymx = $this->yystack[$this->yyidx]->major;
  1871. if ($yymx == self::YYERRORSYMBOL || $yyerrorhit ){
  1872. if (self::$yyTraceFILE) {
  1873. fprintf(self::$yyTraceFILE, "%sDiscard input token %s\n",
  1874. self::$yyTracePrompt, self::$yyTokenName[$yymajor]);
  1875. }
  1876. $this->yy_destructor($yymajor, $yytokenvalue);
  1877. $yymajor = self::YYNOCODE;
  1878. } else {
  1879. while ($this->yyidx >= 0 &&
  1880. $yymx != self::YYERRORSYMBOL &&
  1881. ($yyact = $this->yy_find_shift_action(self::YYERRORSYMBOL)) >= self::YYNSTATE
  1882. ){
  1883. $this->yy_pop_parser_stack();
  1884. }
  1885. if ($this->yyidx < 0 || $yymajor==0) {
  1886. $this->yy_destructor($yymajor, $yytokenvalue);
  1887. $this->yy_parse_failed();
  1888. $yymajor = self::YYNOCODE;
  1889. } elseif ($yymx != self::YYERRORSYMBOL) {
  1890. $u2 = 0;
  1891. $this->yy_shift($yyact, self::YYERRORSYMBOL, $u2);
  1892. }
  1893. }
  1894. $this->yyerrcnt = 3;
  1895. $yyerrorhit = 1;
  1896. } else {
  1897. /* YYERRORSYMBOL is not defined */
  1898. /* This is what we do if the grammar does not define ERROR:
  1899. **
  1900. ** * Report an error message, and throw away the input token.
  1901. **
  1902. ** * If the input token is $, then fail the parse.
  1903. **
  1904. ** As before, subsequent error messages are suppressed until
  1905. ** three input tokens have been successfully shifted.
  1906. */
  1907. if ($this->yyerrcnt <= 0) {
  1908. $this->yy_syntax_error($yymajor, $yytokenvalue);
  1909. }
  1910. $this->yyerrcnt = 3;
  1911. $this->yy_destructor($yymajor, $yytokenvalue);
  1912. if ($yyendofinput) {
  1913. $this->yy_parse_failed();
  1914. }
  1915. $yymajor = self::YYNOCODE;
  1916. }
  1917. } else {
  1918. $this->yy_accept();
  1919. $yymajor = self::YYNOCODE;
  1920. }
  1921. } while ($yymajor != self::YYNOCODE && $this->yyidx >= 0);
  1922. }
  1923. }