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

example

  1. <?php
  2. /* Driver template for the PHP_ParserGenerator 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 ParseyyToken implements ArrayAccess
  12. {
  13.     public $string '';
  14.     public $metadata array();
  15.  
  16.     function __construct($s$m array())
  17.     {
  18.         if ($s instanceof ParseyyToken{
  19.             $this->string $s->string;
  20.             $this->metadata $s->metadata;
  21.         else {
  22.             $this->string = (string) $s;
  23.             if ($m instanceof ParseyyToken{
  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 ParseyyToken?
  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 ParseyyToken{
  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. /** The following structure represents a single element of the
  76.  * parser's stack.  Information stored includes:
  77.  *
  78.  *   +  The state number for the parser at this level of the stack.
  79.  *
  80.  *   +  The value of the token stored at this level of the stack.
  81.  *      (In other words, the "major" token.)
  82.  *
  83.  *   +  The semantic value stored at this level of the stack.  This is
  84.  *      the information used by the action routines in the grammar.
  85.  *      It is sometimes called the "minor" token.
  86.  */
  87. class ParseyyStackEntry
  88. {
  89.     public $stateno;       /* The state-number */
  90.     public $major;         /* The major token value.  This is the code
  91.                      ** number for the token at this stack level */
  92.     public $minor/* The user-supplied minor token value.  This
  93.                      ** is the value of the token  */
  94. };
  95.  
  96. // code external to the class is included here
  97. %%
  98.  
  99. // declare_class is output here
  100. %%
  101. {
  102. /* First off, code is included which follows the "include_class" declaration
  103. ** in the input file. */
  104. %%
  105.  
  106. /* Next is all token values, as class constants
  107. */
  108. /* 
  109. ** These constants (all generated automatically by the parser generator)
  110. ** specify the various kinds of tokens (terminals) that the parser
  111. ** understands. 
  112. **
  113. ** Each symbol here is a terminal symbol in the grammar.
  114. */
  115. %%
  116.  
  117. /* Next are that tables used to determine what action to take based on the
  118. ** current state and lookahead token.  These tables are used to implement
  119. ** functions that take a state number and lookahead value and return an
  120. ** action integer.  
  121. **
  122. ** Suppose the action integer is N.  Then the action is determined as
  123. ** follows
  124. **
  125. **   0 <= N < self::YYNSTATE                              Shift N.  That is,
  126. **                                                        push the lookahead
  127. **                                                        token onto the stack
  128. **                                                        and goto state N.
  129. **
  130. **   self::YYNSTATE <= N < self::YYNSTATE+self::YYNRULE   Reduce by rule N-YYNSTATE.
  131. **
  132. **   N == self::YYNSTATE+self::YYNRULE                    A syntax error has occurred.
  133. **
  134. **   N == self::YYNSTATE+self::YYNRULE+1                  The parser accepts its
  135. **                                                        input. (and concludes parsing)
  136. **
  137. **   N == self::YYNSTATE+self::YYNRULE+2                  No such action.  Denotes unused
  138. **                                                        slots in the yy_action[] table.
  139. **
  140. ** The action table is constructed as a single large static array $yy_action.
  141. ** Given state S and lookahead X, the action is computed as
  142. **
  143. **      self::$yy_action[self::$yy_shift_ofst[S] + X ]
  144. **
  145. ** If the index value self::$yy_shift_ofst[S]+X is out of range or if the value
  146. ** self::$yy_lookahead[self::$yy_shift_ofst[S]+X] is not equal to X or if
  147. ** self::$yy_shift_ofst[S] is equal to self::YY_SHIFT_USE_DFLT, it means that
  148. ** the action is not in the table and that self::$yy_default[S] should be used instead.  
  149. **
  150. ** The formula above is for computing the action when the lookahead is
  151. ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
  152. ** a reduce action) then the static $yy_reduce_ofst array is used in place of
  153. ** the static $yy_shift_ofst array and self::YY_REDUCE_USE_DFLT is used in place of
  154. ** self::YY_SHIFT_USE_DFLT.
  155. **
  156. ** The following are the tables generated in this section:
  157. **
  158. **  self::$yy_action        A single table containing all actions.
  159. **  self::$yy_lookahead     A table containing the lookahead for each entry in
  160. **                          yy_action.  Used to detect hash collisions.
  161. **  self::$yy_shift_ofst    For each state, the offset into self::$yy_action for
  162. **                          shifting terminals.
  163. **  self::$yy_reduce_ofst   For each state, the offset into self::$yy_action for
  164. **                          shifting non-terminals after a reduce.
  165. **  self::$yy_default       Default action for each state.
  166. */
  167. %%
  168. /* The next thing included is series of defines which control
  169. ** various aspects of the generated parser.
  170. **    self::YYNOCODE      is a number which corresponds
  171. **                        to no legal terminal or nonterminal number.  This
  172. **                        number is used to fill in empty slots of the hash 
  173. **                        table.
  174. **    self::YYFALLBACK    If defined, this indicates that one or more tokens
  175. **                        have fall-back values which should be used if the
  176. **                        original value of the token will not parse.
  177. **    self::YYSTACKDEPTH  is the maximum depth of the parser's stack.
  178. **    self::YYNSTATE      the combined number of states.
  179. **    self::YYNRULE       the number of rules in the grammar
  180. **    self::YYERRORSYMBOL is the code number of the error symbol.  If not
  181. **                        defined, then do no error processing.
  182. */
  183. %%
  184.     /** The next table maps tokens into fallback tokens.  If a construct
  185.      * like the following:
  186.      * 
  187.      *      %fallback ID X Y Z.
  188.      *
  189.      * appears in the grammer, then ID becomes a fallback token for X, Y,
  190.      * and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
  191.      * but it does not parse, the type of the token is changed to ID and
  192.      * the parse is retried before an error is thrown.
  193.      */
  194.     static public $yyFallback array(
  195. %%
  196.     );
  197.     /**
  198.      * Turn parser tracing on by giving a stream to which to write the trace
  199.      * and a prompt to preface each trace message.  Tracing is turned off
  200.      * by making either argument NULL
  201.      *
  202.      * Inputs:
  203.      * 
  204.      * - A stream resource to which trace output should be written.
  205.      *   If NULL, then tracing is turned off.
  206.      * - A prefix string written at the beginning of every
  207.      *   line of trace output.  If NULL, then tracing is
  208.      *   turned off.
  209.      *
  210.      * Outputs:
  211.      * 
  212.      * - None.
  213.      * @param resource 
  214.      * @param string 
  215.      */
  216.     static function Trace($TraceFILE$zTracePrompt)
  217.     {
  218.         if (!$TraceFILE{
  219.             $zTracePrompt 0;
  220.         elseif (!$zTracePrompt{
  221.             $TraceFILE 0;
  222.         }
  223.         self::$yyTraceFILE $TraceFILE;
  224.         self::$yyTracePrompt $zTracePrompt;
  225.     }
  226.  
  227.     /**
  228.      * Output debug information to output (php://output stream)
  229.      */
  230.     static function PrintTrace()
  231.     {
  232.         self::$yyTraceFILE fopen('php://output''w');
  233.         self::$yyTracePrompt '';
  234.     }
  235.  
  236.     /**
  237.      * @var resource|0
  238.      */
  239.     static public $yyTraceFILE;
  240.     /**
  241.      * String to prepend to debug output
  242.      * @var string|0
  243.      */
  244.     static public $yyTracePrompt;
  245.     /**
  246.      * @var int 
  247.      */
  248.     public $yyidx;                    /* Index of top element in stack */
  249.     /**
  250.      * @var int 
  251.      */
  252.     public $yyerrcnt;                 /* Shifts left before out of the error */
  253.     /**
  254.      * @var array 
  255.      */
  256.     public $yystack array();  /* The parser's stack */
  257.  
  258.     /**
  259.      * For tracing shifts, the names of all terminals and nonterminals
  260.      * are required.  The following table supplies these names
  261.      * @var array 
  262.      */
  263.     static public $yyTokenName array
  264. %%
  265.     );
  266.  
  267.     /**
  268.      * For tracing reduce actions, the names of all rules are required.
  269.      * @var array 
  270.      */
  271.     static public $yyRuleName array(
  272. %%
  273.     );
  274.  
  275.     /**
  276.      * This function returns the symbolic name associated with a token
  277.      * value.
  278.      * @param int 
  279.      * @return string 
  280.      */
  281.     function tokenName($tokenType)
  282.     {
  283.         if ($tokenType === 0{
  284.             return 'End of Input';
  285.         }
  286.         if ($tokenType && $tokenType count(self::$yyTokenName)) {
  287.             return self::$yyTokenName[$tokenType];
  288.         else {
  289.             return "Unknown";
  290.         }
  291.     }
  292.  
  293.     /**
  294.      * The following function deletes the value associated with a
  295.      * symbol.  The symbol can be either a terminal or nonterminal.
  296.      * @param int the symbol code
  297.      * @param mixed the symbol's value
  298.      */
  299.     static function yy_destructor($yymajor$yypminor)
  300.     {
  301.         switch ($yymajor{
  302.         /* Here is inserted the actions which take place when a
  303.         ** terminal or non-terminal is destroyed.  This can happen
  304.         ** when the symbol is popped from the stack during a
  305.         ** reduce or during error processing or when a parser is 
  306.         ** being destroyed before it is finished parsing.
  307.         **
  308.         ** Note: during a reduce, the only symbols destroyed are those
  309.         ** which appear on the RHS of the rule, but which are not used
  310.         ** inside the C code.
  311.         */
  312. %%
  313.             default:  break;   /* If no destructor action specified: do nothing */
  314.         }
  315.     }
  316.  
  317.     /**
  318.      * Pop the parser's stack once.
  319.      *
  320.      * If there is a destructor routine associated with the token which
  321.      * is popped from the stack, then call it.
  322.      *
  323.      * Return the major token number for the symbol popped.
  324.      * @param ParseyyParser 
  325.      * @return int 
  326.      */
  327.     function yy_pop_parser_stack()
  328.     {
  329.         if (!count($this->yystack)) {
  330.             return;
  331.         }
  332.         $yytos array_pop($this->yystack);
  333.         if (self::$yyTraceFILE && $this->yyidx >= 0{
  334.             fwrite(self::$yyTraceFILE,
  335.                 self::$yyTracePrompt 'Popping ' self::$yyTokenName[$yytos->major.
  336.                     "\n");
  337.         }
  338.         $yymajor $yytos->major;
  339.         self::yy_destructor($yymajor$yytos->minor);
  340.         $this->yyidx--;
  341.         return $yymajor;
  342.     }
  343.  
  344.     /**
  345.      * Deallocate and destroy a parser.  Destructors are all called for
  346.      * all stack elements before shutting the parser down.
  347.      */
  348.     function __destruct()
  349.     {
  350.         while ($this->yyidx >= 0{
  351.             $this->yy_pop_parser_stack();
  352.         }
  353.         if (is_resource(self::$yyTraceFILE)) {
  354.             fclose(self::$yyTraceFILE);
  355.         }
  356.     }
  357.  
  358.     /**
  359.      * Based on the current state and parser stack, get a list of all
  360.      * possible lookahead tokens
  361.      * @param int 
  362.      * @return array 
  363.      */
  364.     function yy_get_expected_tokens($token)
  365.     {
  366.         $state $this->yystack[$this->yyidx]->stateno;
  367.         $expected self::$yyExpectedTokens[$state];
  368.         if (in_array($tokenself::$yyExpectedTokens[$state]true)) {
  369.             return $expected;
  370.         }
  371.         $stack $this->yystack;
  372.         $yyidx $this->yyidx;
  373.         do {
  374.             $yyact $this->yy_find_shift_action($token);
  375.             if ($yyact >= self::YYNSTATE && $yyact self::YYNSTATE self::YYNRULE{
  376.                 // reduce action
  377.                 $done 0;
  378.                 do {
  379.                     if ($done++ == 100{
  380.                         $this->yyidx $yyidx;
  381.                         $this->yystack $stack;
  382.                         // too much recursion prevents proper detection
  383.                         // so give up
  384.                         return array_unique($expected);
  385.                     }
  386.                     $yyruleno $yyact self::YYNSTATE;
  387.                     $this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs'];
  388.                     $nextstate $this->yy_find_reduce_action(
  389.                         $this->yystack[$this->yyidx]->stateno,
  390.                         self::$yyRuleInfo[$yyruleno]['lhs']);
  391.                     if (isset(self::$yyExpectedTokens[$nextstate])) {
  392.                         $expected += self::$yyExpectedTokens[$nextstate];
  393.                             if (in_array($token,
  394.                                   self::$yyExpectedTokens[$nextstate]true)) {
  395.                             $this->yyidx $yyidx;
  396.                             $this->yystack $stack;
  397.                             return array_unique($expected);
  398.                         }
  399.                     }
  400.                     if ($nextstate self::YYNSTATE{
  401.                         // we need to shift a non-terminal
  402.                         $this->yyidx++;
  403.                         $x new ParseyyStackEntry;
  404.                         $x->stateno $nextstate;
  405.                         $x->major self::$yyRuleInfo[$yyruleno]['lhs'];
  406.                         $this->yystack[$this->yyidx$x;
  407.                         continue 2;
  408.                     elseif ($nextstate == self::YYNSTATE self::YYNRULE 1{
  409.                         $this->yyidx $yyidx;
  410.                         $this->yystack $stack;
  411.                         // the last token was just ignored, we can't accept
  412.                         // by ignoring input, this is in essence ignoring a
  413.                         // syntax error!
  414.                         return array_unique($expected);
  415.                     elseif ($nextstate === self::YY_NO_ACTION{
  416.                         $this->yyidx $yyidx;
  417.                         $this->yystack $stack;
  418.                         // input accepted, but not shifted (I guess)
  419.                         return $expected;
  420.                     else {
  421.                         $yyact $nextstate;
  422.                     }
  423.                 while (true);
  424.             }
  425.             break;
  426.         while (true);
  427.         return array_unique($expected);
  428.     }
  429.  
  430.     /**
  431.      * Based on the parser state and current parser stack, determine whether
  432.      * the lookahead token is possible.
  433.      * 
  434.      * The parser will convert the token value to an error token if not.  This
  435.      * catches some unusual edge cases where the parser would fail.
  436.      * @param int 
  437.      * @return bool 
  438.      */
  439.     function yy_is_expected_token($token)
  440.     {
  441.         if ($token === 0{
  442.             return true// 0 is not part of this
  443.         }
  444.         $state $this->yystack[$this->yyidx]->stateno;
  445.         if (in_array($tokenself::$yyExpectedTokens[$state]true)) {
  446.             return true;
  447.         }
  448.         $stack $this->yystack;
  449.         $yyidx $this->yyidx;
  450.         do {
  451.             $yyact $this->yy_find_shift_action($token);
  452.             if ($yyact >= self::YYNSTATE && $yyact self::YYNSTATE self::YYNRULE{
  453.                 // reduce action
  454.                 $done 0;
  455.                 do {
  456.                     if ($done++ == 100{
  457.                         $this->yyidx $yyidx;
  458.                         $this->yystack $stack;
  459.                         // too much recursion prevents proper detection
  460.                         // so give up
  461.                         return true;
  462.                     }
  463.                     $yyruleno $yyact self::YYNSTATE;
  464.                     $this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs'];
  465.                     $nextstate $this->yy_find_reduce_action(
  466.                         $this->yystack[$this->yyidx]->stateno,
  467.                         self::$yyRuleInfo[$yyruleno]['lhs']);
  468.                     if (isset(self::$yyExpectedTokens[$nextstate]&&
  469.                           in_array($tokenself::$yyExpectedTokens[$nextstate]true)) {
  470.                         $this->yyidx $yyidx;
  471.                         $this->yystack $stack;
  472.                         return true;
  473.                     }
  474.                     if ($nextstate self::YYNSTATE{
  475.                         // we need to shift a non-terminal
  476.                         $this->yyidx++;
  477.                         $x new ParseyyStackEntry;
  478.                         $x->stateno $nextstate;
  479.                         $x->major self::$yyRuleInfo[$yyruleno]['lhs'];
  480.                         $this->yystack[$this->yyidx$x;
  481.                         continue 2;
  482.                     elseif ($nextstate == self::YYNSTATE self::YYNRULE 1{
  483.                         $this->yyidx $yyidx;
  484.                         $this->yystack $stack;
  485.                         if (!$token{
  486.                             // end of input: this is valid
  487.                             return true;
  488.                         }
  489.                         // the last token was just ignored, we can't accept
  490.                         // by ignoring input, this is in essence ignoring a
  491.                         // syntax error!
  492.                         return false;
  493.                     elseif ($nextstate === self::YY_NO_ACTION{
  494.                         $this->yyidx $yyidx;
  495.                         $this->yystack $stack;
  496.                         // input accepted, but not shifted (I guess)
  497.                         return true;
  498.                     else {
  499.                         $yyact $nextstate;
  500.                     }
  501.                 while (true);
  502.             }
  503.             break;
  504.         while (true);
  505.         return true;
  506.     }
  507.  
  508.     /**
  509.      * Find the appropriate action for a parser given the terminal
  510.      * look-ahead token iLookAhead.
  511.      *
  512.      * If the look-ahead token is YYNOCODE, then check to see if the action is
  513.      * independent of the look-ahead.  If it is, return the action, otherwise
  514.      * return YY_NO_ACTION.
  515.      * @param int The look-ahead token
  516.      */
  517.     function yy_find_shift_action($iLookAhead)
  518.     {
  519.         $stateno $this->yystack[$this->yyidx]->stateno;
  520.      
  521.         /* if ($this->yyidx < 0) return self::YY_NO_ACTION;  */
  522.         if (!isset(self::$yy_shift_ofst[$stateno])) {
  523.             // no shift actions
  524.             return self::$yy_default[$stateno];
  525.         }
  526.         $i self::$yy_shift_ofst[$stateno];
  527.         if ($i === self::YY_SHIFT_USE_DFLT{
  528.             return self::$yy_default[$stateno];
  529.         }
  530.         if ($iLookAhead == self::YYNOCODE{
  531.             return self::YY_NO_ACTION;
  532.         }
  533.         $i += $iLookAhead;
  534.         if ($i || $i >= self::YY_SZ_ACTTAB ||
  535.               self::$yy_lookahead[$i!= $iLookAhead{
  536.             if (count(self::$yyFallback&& $iLookAhead count(self::$yyFallback)
  537.                    && ($iFallback self::$yyFallback[$iLookAhead]!= 0{
  538.                 if (self::$yyTraceFILE{
  539.                     fwrite(self::$yyTraceFILEself::$yyTracePrompt "FALLBACK " .
  540.                         self::$yyTokenName[$iLookAhead" => " .
  541.                         self::$yyTokenName[$iFallback"\n");
  542.                 }
  543.                 return $this->yy_find_shift_action($iFallback);
  544.             }
  545.             return self::$yy_default[$stateno];
  546.         else {
  547.             return self::$yy_action[$i];
  548.         }
  549.     }
  550.  
  551.     /**
  552.      * Find the appropriate action for a parser given the non-terminal
  553.      * look-ahead token $iLookAhead.
  554.      *
  555.      * If the look-ahead token is self::YYNOCODE, then check to see if the action is
  556.      * independent of the look-ahead.  If it is, return the action, otherwise
  557.      * return self::YY_NO_ACTION.
  558.      * @param int Current state number
  559.      * @param int The look-ahead token
  560.      */
  561.     function yy_find_reduce_action($stateno$iLookAhead)
  562.     {
  563.         /* $stateno = $this->yystack[$this->yyidx]->stateno; */
  564.  
  565.         if (!isset(self::$yy_reduce_ofst[$stateno])) {
  566.             return self::$yy_default[$stateno];
  567.         }
  568.         $i self::$yy_reduce_ofst[$stateno];
  569.    &n