phpDocumentor PHP_ParserGenerator
[ class tree: PHP_ParserGenerator ] [ index: PHP_ParserGenerator ] [ all elements ]

Sample parser file format PHP code (PHP_LexerGenerator's parser)

  1. <?php
  2. /* Driver template for the PHP_PHP_LexerGenerator_ParserrGenerator parser generator. (PHP port of LEMON)
  3. */
  4.  
  5. /**
  6.  * This can be used to store both the string representation of
  7.  * a token, and any useful meta-data associated with the token.
  8.  *
  9.  * meta-data should be stored as an array
  10.  */
  11. class PHP_LexerGenerator_ParseryyToken implements ArrayAccess
  12. {
  13.     public $string '';
  14.     public $metadata array();
  15.  
  16.     function __construct($s$m array())
  17.     {
  18.         if ($s instanceof PHP_LexerGenerator_ParseryyToken{
  19.             $this->string $s->string;
  20.             $this->metadata $s->metadata;
  21.         else {
  22.             $this->string = (string) $s;
  23.             if ($m instanceof PHP_LexerGenerator_ParseryyToken{
  24.                 $this->metadata $m->metadata;
  25.             elseif (is_array($m)) {
  26.                 $this->metadata $m;
  27.             }
  28.         }
  29.     }
  30.  
  31.     function __toString()
  32.     {
  33.         return $this->_string;
  34.     }
  35.  
  36.     function offsetExists($offset)
  37.     {
  38.         return isset($this->metadata[$offset]);
  39.     }
  40.  
  41.     function offsetGet($offset)
  42.     {
  43.         return $this->metadata[$offset];
  44.     }
  45.  
  46.     function offsetSet($offset$value)
  47.     {
  48.         if ($offset === null{
  49.             if (isset($value[0])) {
  50.                 $x ($value instanceof PHP_LexerGenerator_ParseryyToken?
  51.                     $value->metadata $value;
  52.                 $this->metadata array_merge($this->metadata$x);
  53.                 return;
  54.             }
  55.             $offset count($this->metadata);
  56.         }
  57.         if ($value === null{
  58.             return;
  59.         }
  60.         if ($value instanceof PHP_LexerGenerator_ParseryyToken{
  61.             if ($value->metadata{
  62.                 $this->metadata[$offset$value->metadata;
  63.             }
  64.         elseif ($value{
  65.             $this->metadata[$offset$value;
  66.         }
  67.     }
  68.  
  69.     function offsetUnset($offset)
  70.     {
  71.         unset($this->metadata[$offset]);
  72.     }
  73. }
  74.  
  75. // code external to the class is included here
  76. #line 3 "LexerGenerator\Parser.y"
  77.  
  78. /* ?><?php {//*/
  79. /**
  80.  * PHP_LexerGenerator, a php 5 lexer generator.
  81.  * 
  82.  * This lexer generator translates a file in a format similar to
  83.  * re2c ({@link http://re2c.org}) and translates it into a PHP 5-based lexer
  84.  *
  85.  * PHP version 5
  86.  *
  87.  * LICENSE: This source file is subject to version 3.01 of the PHP license
  88.  * that is available through the world-wide-web at the following URI:
  89.  * http://www.php.net/license/3_01.txt.  If you did not receive a copy of
  90.  * the PHP License and are unable to obtain it through the web, please
  91.  * send a note to license@php.net so we can mail you a copy immediately.
  92.  *
  93.  * @category   php
  94.  * @package    PHP_LexerGenerator
  95.  * @author     Gregory Beaver <cellog@php.net>
  96.  * @copyright  2006 Gregory Beaver
  97.  * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
  98.  * @version    CVS: $Id$
  99.  * @since      File available since Release 0.1.0
  100.  */
  101. /**
  102.  * Token parser for plex files.
  103.  * 
  104.  * This parser converts tokens pulled from {@link PHP_LexerGenerator_Lexer}
  105.  * into abstract patterns and rules, then creates the output file
  106.  * @package    PHP_LexerGenerator
  107.  * @author     Gregory Beaver <cellog@php.net>
  108.  * @copyright  2006 Gregory Beaver
  109.  * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
  110.  * @version    @package_version@
  111.  * @since      Class available since Release 0.1.0
  112.  */
  113. #line 115 "LexerGenerator\Parser.php"
  114.  
  115. /** The following structure represents a single element of the
  116.  * parser's stack.  Information stored includes:
  117.  *
  118.  *   +  The state number for the parser at this level of the stack.
  119.  *
  120.  *   +  The value of the token stored at this level of the stack.
  121.  *      (In other words, the "major" token.)
  122.  *
  123.  *   +  The semantic value stored at this level of the stack.  This is
  124.  *      the information used by the action routines in the grammar.
  125.  *      It is sometimes called the "minor" token.
  126.  */
  127. class PHP_LexerGenerator_ParseryyStackEntry
  128. {
  129.     public $stateno;       /* The state-number */
  130.     public $major;         /* The major token value.  This is the code
  131.                      ** number for the token at this stack level */
  132.     public $minor/* The user-supplied minor token value.  This
  133.                      ** is the value of the token  */
  134. };
  135.  
  136. // any extra class_declaration (extends/implements) are defined here
  137. /**
  138.  * The state of the parser is completely contained in an instance of
  139.  * the following structure
  140.  */
  141. #line 2 "LexerGenerator\Parser.y"
  142. class PHP_LexerGenerator_Parser#line 145 "LexerGenerator\Parser.php"
  143. {
  144. /* First off, code is included which follows the "include_class" declaration
  145. ** in the input file. */
  146. #line 52 "LexerGenerator\Parser.y"
  147.  
  148.     
  149.     private $patterns;
  150.     private $out;
  151.     private $lex;
  152.     private $input;
  153.     private $counter;
  154.     private $token;
  155.     private $value;
  156.     private $line;
  157.  
  158.     public $transTable array(
  159.         => self::PHPCODE,
  160.         => self::COMMENTSTART,
  161.         => self::COMMENTEND,
  162.         => self::QUOTE,
  163.         => self::PATTERN,
  164.         => self::CODE,
  165.         => self::SUBPATTERN,
  166.         => self::PI,
  167.     );
  168.  
  169.     function __construct($outfile$lex)
  170.     {
  171.         $this->out fopen($outfile'wb');
  172.         if (!$this->out{
  173.             throw new Exception('unable to open lexer output file "' $outfile '"');
  174.         }
  175.         $this->lex $lex;
  176.     }
  177.  
  178.     function outputRules($rules$statename)
  179.     {
  180.         static $ruleindex 1;
  181.         $patterns array();
  182.         $pattern '/';
  183.         foreach ($rules as $rule{
  184.             $patterns['^(' $rule['pattern'')';
  185.         }
  186.         $pattern .= implode('|'$patterns);
  187.         $pattern .= '/';
  188.         if ($statename{
  189.             fwrite($this->out'
  190.     const ' $statename ' = ' $ruleindex ';
  191. ');
  192.         }
  193.         fwrite($this->out'
  194.     function yylex' $ruleindex '()
  195.     {
  196.         if (' $this->counter ' >= strlen(' $this->input ')) {
  197.             return false; // end of input
  198.         }
  199.         ');
  200.         fwrite($this->out'    $yy_global_pattern = "' .
  201.             $pattern '";' "\n");
  202.         fwrite($this->out'
  203.         do {
  204.             if (preg_match($yy_global_pattern, substr(' $this->input ', ' .
  205.              $this->counter .
  206.                     '), $yymatches)) {
  207.                 $yymatches = array_filter($yymatches, \'strlen\'); // remove empty sub-patterns
  208.                 if (!count($yymatches)) {
  209.                     throw new Exception(\'Error: lexing failed because a rule matched\' .
  210.                         \'an empty string\');
  211.                 }
  212.                 next($yymatches); // skip global match
  213.                 ' $this->token ' = key($yymatches); // token number
  214.                 ' $this->value ' = current($yymatches); // token value
  215.                 $r = $this->{\'yy_r' $ruleindex '_\' . ' $this->token '}();
  216.                 if ($r === null) {
  217.                     ' $this->counter ' += strlen($this->value);
  218.                     ' $this->line ' += substr_count("\n", ' $this->value ');
  219.                     // accept this token
  220.                     return true;
  221.                 } elseif ($r === true) {
  222.                     // we have changed state
  223.                     // process this token in the new state
  224.                     return $this->yylex();
  225.                 } elseif ($r === false) {
  226.                     ' $this->counter ' += strlen($this->value);
  227.                     ' $this->line ' += substr_count("\n", ' $this->value ');
  228.                     if (' $this->counter ' >= strlen(' $this->input ')) {
  229.                         return false; // end of input
  230.                     }
  231.                     // skip this token
  232.                     continue;
  233.                 } else {');
  234.         fwrite($this->out'                    $yy_yymore_patterns = array(' "\n");
  235.         for($i 0count($patterns)$i++{
  236.             unset($patterns[$i]);
  237.             fwrite($this->out'        ' ($i 1' => "' .
  238.                 implode('|'$patterns"\",\n");
  239.         }
  240.         fwrite($this->out'    );' "\n");
  241.         fwrite($this->out'
  242.                     // yymore is needed
  243.                     do {
  244.                         if (!strlen($yy_yymore_patterns[' $this->token '])) {
  245.                             throw new Exception(\'cannot do yymore for the last token\');
  246.                         }
  247.                         if (preg_match($yy_yymore_patterns[' $this->token '],
  248.                               substr(' $this->input ', ' $this->counter '), $yymatches)) {
  249.                             $yymatches = array_filter($yymatches, \'strlen\'); // remove empty sub-patterns
  250.                             next($yymatches); // skip global match
  251.                             ' $this->token ' = key($yymatches); // token number
  252.                             ' $this->value ' = current($yymatches); // token value
  253.                             ' $this->line ' = substr_count("\n", ' $this->value ');
  254.                         }
  255.                     } while ($this->{\'yy_r' $ruleindex '_\' . ' $this->token '}() !== null);
  256.                     // accept
  257.                     ' $this->counter ' += strlen($this->value);
  258.                     ' $this->line ' += substr_count("\n", ' $this->value ');
  259.                     return true;
  260.                 }
  261.             } else {
  262.                 throw new Exception(\'Unexpected input at line\' . ' $this->line ' .
  263.                     \': \' . ' $this->input '[' $this->counter ']);
  264.             }
  265.             break;
  266.         } while (true);
  267.     } // end function
  268.  
  269. ');
  270.         foreach ($rules as $i => $rule{
  271.             fwrite($this->out'    function yy_r' $ruleindex '_' ($i 1'()
  272.     {
  273. $rule['code'.
  274. '    }
  275. ');
  276.         }
  277.         $ruleindex++// for next set of rules
  278.     }
  279.  
  280.     function error($msg)
  281.     {
  282.         echo 'Error on line ' $this->lex->line ': ' $msg;
  283.     }
  284.  
  285.     function _validatePattern($pattern)
  286.     {
  287.         if ($pattern[0== '^'{
  288.             $this->error('Pattern "' $pattern .
  289.                 '" should not begin with ^, lexer may fail');
  290.         }
  291.         if ($pattern[strlen($pattern1== '$'{
  292.             $this->error('Pattern "' $pattern .
  293.                 '" should not end with $, lexer may fail');
  294.         }
  295.         // match ( but not \( or (?:
  296.         $savepattern $pattern;
  297.         $pattern str_replace('\\\\'''$pattern);
  298.         $pattern str_replace('\\('''$pattern);
  299.         if (preg_match('/\([^?][^:]|\(\?[^:]|\(\?$|\($/'$pattern)) {
  300.             $this->error('Pattern "' $savepattern .
  301.                 '" must not contain sub-patterns (like this), generated lexer will fail');
  302.         }
  303.     }
  304. #line 307 "LexerGenerator\Parser.php"
  305.  
  306. /* Next is all token values, in a form suitable for use by makeheaders.
  307. ** This section will be null unless lemon is run with the -m switch.
  308. */
  309. /* 
  310. ** These constants (all generated automatically by the parser generator)
  311. ** specify the various kinds of tokens (terminals) that the parser
  312. ** understands. 
  313. **
  314. ** Each symbol here is a terminal symbol in the grammar.
  315. */
  316.     const PHPCODE                        =  1;
  317.     const COMMENTSTART                   =  2;
  318.     const COMMENTEND                     =  3;
  319.     const PI                             =  4;
  320.     const SUBPATTERN                     =  5;
  321.     const CODE                           =  6;
  322.     const PATTERN                        =  7;
  323.     const QUOTE                          =  8;
  324.     const YY_NO_ACTION 94;
  325.     const YY_ACCEPT_ACTION 93;
  326.     const YY_ERROR_ACTION 92;
  327.  
  328. /* Next are that tables used to determine what action to take based on the
  329. ** current state and lookahead token.  These tables are used to implement
  330. ** functions that take a state number and lookahead value and return an
  331. ** action integer.  
  332. **
  333. ** Suppose the action integer is N.  Then the action is determined as
  334. ** follows
  335. **
  336. **   0 <= N < YYNSTATE                  Shift N.  That is, push the lookahead
  337. **                                      token onto the stack and goto state N.
  338. **
  339. **   YYNSTATE <= N < YYNSTATE+YYNRULE   Reduce by rule N-YYNSTATE.
  340. **
  341. **   N == YYNSTATE+YYNRULE              A syntax error has occurred.
  342. **
  343. **   N == YYNSTATE+YYNRULE+1            The parser accepts its input.
  344. **
  345. **   N == YYNSTATE+YYNRULE+2            No such action.  Denotes unused
  346. **                                      slots in the yy_action[] table.
  347. **
  348. ** The action table is constructed as a single large table named yy_action[].
  349. ** Given state S and lookahead X, the action is computed as
  350. **
  351. **      yy_action[ yy_shift_ofst[S] + X ]
  352. **
  353. ** If the index value yy_shift_ofst[S]+X is out of range or if the value
  354. ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
  355. ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
  356. ** and that yy_default[S] should be used instead.  
  357. **
  358. ** The formula above is for computing the action when the lookahead is
  359. ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
  360. ** a reduce action) then the yy_reduce_ofst[] array is used in place of
  361. ** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
  362. ** YY_SHIFT_USE_DFLT.
  363. **
  364. ** The following are the tables generated in this section:
  365. **
  366. **  yy_action[]        A single table containing all actions.
  367. **  yy_lookahead[]     A table containing the lookahead for each entry in
  368. **                     yy_action.  Used to detect hash collisions.
  369. **  yy_shift_ofst[]    For each state, the offset into yy_action for
  370. **                     shifting terminals.
  371. **  yy_reduce_ofst[]   For each state, the offset into yy_action for
  372. **                     shifting non-terminals after a reduce.
  373. **  yy_default[]       Default action for each state.
  374. */
  375.     const YY_SZ_ACTTAB 87;
  376. static public $yy_action array(
  377.  /*     0 */        33,   31,   58,   58,    3,   50,   50,   57,   44,   39,
  378.  /*    10 */        42,   58,   57,   55,   50,   42,   51,   36,   58,   58,
  379.  /*    20 */        59,   50,   50,   38,   58,   46,   45,   50,   35,   58,
  380.  /*    30 */        17,    2,   50,   93,   52,   16,   18,    6,   24,   19,
  381.  /*    40 */          2,   12,   41,   53,   48,   40,   30,   60,    1,    4,
  382.  /*    50 */        34,   10,   20,   43,   49,   32,   14,   58,    7,   20,
  383.  /*    60 */        50,    8,   20,    9,   20,   37,   47,   11,   20,   56,
  384.  /*    70 */        15,    5,   22,   54,   28,   23,   53,   21,   29,   25,
  385.  /*    80 */          2,   27,    6,   13,   53,   53,   26,
  386.     );
  387.     static public $yy_lookahead array(
  388.  /*     0 */          3,    3,    5,    5,    5,    8,    8,    5,    6,    3,
  389.  /*    10 */          8,    5,    5,    6,    8,    8,    3,    3,    5,    5,
  390.  /*    20 */          3,    8,    8,    4,    5,    5,    6,    8,    4,    5,
  391.  /*    30 */          1,    2,    8,   10,   11,   12,    1,    2,    4,    1,
  392.  /*    40 */          2,    7,    5,    1,    5,    8,   16,    8,    2,    5,
  393.  /*    50 */          4,   18,   19,    5,    6,   14,   15,    5,   18,   19,
  394.  /*    60 */          8,   18,   19,   18,   19,    5,    1,   18,   19,    1,
  395.  /*    70 */          7,    2,   13,    1,   17,   13,   20,   19,    4,   13,
  396.  /*    80 */          2,   17,    2,   12,   20,   20,   13,
  397. );
  398.     const YY_SHIFT_USE_DFLT = -4;
  399.     const YY_SHIFT_MAX 39;
  400.     static public $yy_shift_ofst array(
  401.  /*     0 */        35,   24,   19,   52,   52,   52,   74,   13,   -2,   -3,
  402.  /*    10 */        14,    6,   37,   38,   34,   37,   29,   78,   80,   78,
  403.  /*    20 */          7,    2,   46,   46,   48,   46,   46,   39,   39,   20,
  404.  /*    30 */        63,   42,   17,   72,   60,   -1,   68,   69,   44,   65,
  405. );
  406.     const YY_REDUCE_USE_DFLT = -1;
  407.     const YY_REDUCE_MAX 19;
  408.     static public $yy_reduce_ofst array(
  409.  /*     0 */        23,   49,   45,   33,   43,   40,   41,   58,   58,   58,
  410.  /*    10 */        58,   58,   64,   59,   30,   57,   62,   73,   71,   66,
  411. );
  412.     static public $yyExpectedTokens array(
  413.         /* 0 */  array(12),
  414.         /* 1 */  array(458),
  415.         /* 2 */  array(458),
  416.         /* 3 */  array(58),
  417.         /* 4 */  array(58),
  418.         /* 5 */  array(58),
  419.         /* 6 */  array(4),
  420.         /* 7 */  array(358),
  421.         /* 8 */  array(358),
  422.         /* 9 */  array(358),
  423.         /* 10 */  array(358),
  424.         /* 11 */  array(358),
  425.         /* 12 */  array(58),
  426.         /* 13 */  array(12),
  427.         /* 14 */  array(47),
  428.         /* 15 */  array(58),
  429.         /* 16 */  array(12),
  430.         /* 17 */  array(2),
  431.         /* 18 */  array(2),
  432.         /* 19 */  array(2),
  433.         /* 20 */  array(568),
  434.         /* 21 */  array(568),
  435.         /* 22 */  array(24),
  436.         /* 23 */  array(24),
  437.         /* 24 */  array(56),
  438.         /* 25 */  array(24),
  439.         /* 26 */  array(24),
  440.         /* 27 */  array(58),
  441.         /* 28 */  array(58),
  442.         /* 29 */  array(56),
  443.         /* 30 */  array(7),
  444.         /* 31 */  array(1),
  445.         /* 32 */  array(3),
  446.         /* 33 */  array(1),
  447.         /* 34 */  array(5),
  448.         /* 35 */  array(5),
  449.         /* 36 */  array(1),
  450.         /* 37 */  array(2),
  451.         /* 38 */  array(5),
  452.         /* 39 */  array(1),
  453.         /* 40 */  array(),
  454.         /* 41 */  array(),
  455.         /* 42 */  array(),
  456.         /* 43 */  array(),
  457.         /* 44 */  array(),
  458.         /* 45 */  array(),
  459.         /* 46 */  array(),
  460.         /* 47 */  array(),
  461.         /* 48 */  array(),
  462.         /* 49 */  array(),
  463.         /* 50 */  array(),
  464.         /* 51 */  array(),
  465.         /* 52 */  array(),
  466.         /* 53 */  array(),
  467.         /* 54 */  array(),
  468.         /* 55 */  array(),
  469.         /* 56 */  array(),
  470.         /* 57 */  array(),
  471.         /* 58 */  array(),
  472.         /* 59 */  array(),
  473.         /* 60 */  array(),
  474. );
  475.     static public $yy_default array(
  476.  /*     0 */ &n