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

Source for file Data.php

Documentation is available at Data.php

  1. <?php
  2. /**
  3.  * PHP_ParserGenerator, a php 5 parser generator.
  4.  * 
  5.  * This is a direct port of the Lemon parser generator, found at
  6.  * {@link http://www.hwaci.com/sw/lemon/}
  7.  *
  8.  * PHP version 5
  9.  *
  10.  * LICENSE:
  11.  * 
  12.  * Copyright (c) 2006, Gregory Beaver <cellog@php.net>
  13.  * All rights reserved.
  14.  *
  15.  * Redistribution and use in source and binary forms, with or without
  16.  * modification, are permitted provided that the following conditions
  17.  * are met:
  18.  *
  19.  *     * Redistributions of source code must retain the above copyright
  20.  *       notice, this list of conditions and the following disclaimer.
  21.  *     * Redistributions in binary form must reproduce the above copyright
  22.  *       notice, this list of conditions and the following disclaimer in
  23.  *       the documentation and/or other materials provided with the distribution.
  24.  *     * Neither the name of the PHP_ParserGenerator nor the names of its
  25.  *       contributors may be used to endorse or promote products derived
  26.  *       from this software without specific prior written permission.
  27.  *
  28.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  29.  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  30.  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  31.  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  32.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  33.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  34.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  35.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  36.  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  37.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  38.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  39.  *
  40.  * @category   php
  41.  * @package    PHP_ParserGenerator
  42.  * @author     Gregory Beaver <cellog@php.net>
  43.  * @copyright  2006 Gregory Beaver
  44.  * @license    http://www.opensource.org/licenses/bsd-license.php New BSD License
  45.  * @version    CVS: $Id$
  46.  * @since      File available since Release 0.1.0
  47.  */
  48. /**
  49. /**
  50.  * The state vector for the entire parser generator is recorded in
  51.  * this class.
  52.  * 
  53.  * @package    PHP_ParserGenerator
  54.  * @author     Gregory Beaver <cellog@php.net>
  55.  * @copyright  2006 Gregory Beaver
  56.  * @license    http://www.opensource.org/licenses/bsd-license.php New BSD License
  57.  * @version    @package_version@
  58.  * @since      Class available since Release 0.1.0
  59.  */
  60.  
  61. {
  62.     /**
  63.      * Used for terminal and non-terminal offsets into the action table
  64.      * when their default should be used instead
  65.      */
  66.     const NO_OFFSET = -2147483647;
  67.     /**
  68.      * Table of states sorted by state number
  69.      * @var array array of {@link PHP_ParserGenerator_State} objects
  70.      */
  71.     public $sorted;
  72.     /**
  73.      * List of all rules
  74.      * @var PHP_ParserGenerator_Rule 
  75.      */
  76.     public $rule;
  77.     /**
  78.      * Number of states
  79.      * @var int 
  80.      */
  81.     public $nstate;
  82.     /**
  83.      * Number of rules
  84.      * @var int 
  85.      */
  86.     public $nrule;
  87.     /**
  88.      * Number of terminal and nonterminal symbols
  89.      * @var int 
  90.      */
  91.     public $nsymbol;
  92.     /**
  93.      * Number of terminal symbols (tokens)
  94.      * @var int 
  95.      */
  96.     public $nterminal;
  97.     /**
  98.      * Sorted array of pointers to symbols
  99.      * @var array array of {@link PHP_ParserGenerator_Symbol} objects
  100.      */
  101.     public $symbols = array();
  102.     /**
  103.      * Number of errors
  104.      * @var int 
  105.      */
  106.     public $errorcnt;
  107.     /**
  108.      * The error symbol
  109.      * @var PHP_ParserGenerator_Symbol 
  110.      */
  111.     public $errsym;
  112.     /**
  113.      * Name of the generated parser
  114.      * @var string 
  115.      */
  116.     public $name;
  117.     /**
  118.      * Unused relic from the C version
  119.      * 
  120.      * Type of terminal symbols in the parser stack
  121.      * @var string 
  122.      */
  123.     public $tokentype;
  124.     /**
  125.      * Unused relic from the C version
  126.      * 
  127.      * The default type of non-terminal symbols
  128.      * @var string 
  129.      */
  130.     public $vartype;
  131.     /**
  132.      * Name of the start symbol for the grammar
  133.      * @var string 
  134.      */
  135.     public $start;
  136.     /**
  137.      * Size of the parser stack
  138.      * 
  139.      * This is 100 by default, but is set with the %stack_size directive
  140.      * @var int 
  141.      */
  142.     public $stacksize;
  143.     /**
  144.      * Code to put at the start of the parser file
  145.      * 
  146.      * This is set by the %include directive
  147.      * @var string 
  148.      */
  149.     public $include_code;
  150.     /**
  151.      * Line number for start of include code
  152.      * @var int 
  153.      */
  154.     public $includeln;
  155.     /**
  156.      * Code to put in the parser class
  157.      * 
  158.      * This is set by the %include_class directive
  159.      * @var string 
  160.      */
  161.     public $include_classcode;
  162.     /**
  163.      * Line number for start of include code
  164.      * @var int 
  165.      */
  166.     public $include_classln;
  167.     /**
  168.      * any extends/implements code
  169.      * 
  170.      * This is set by the %declare_class directive
  171.      * @var string 
  172.      */
  173.     /**
  174.      * Line number for class declaration code
  175.      * @var int 
  176.      */
  177.     public $declare_classcode;
  178.     /**
  179.      * Line number for start of class declaration code
  180.      * @var int 
  181.      */
  182.     public $declare_classln;
  183.     /**
  184.      * Code to execute when a syntax error is seen
  185.      * 
  186.      * This is set by the %syntax_error directive
  187.      * @var string 
  188.      */
  189.     public $error;
  190.     /**
  191.      * Line number for start of error code
  192.      * @var int 
  193.      */
  194.     public $errorln;
  195.     /**
  196.      * Code to execute on a stack overflow
  197.      * 
  198.      * This is set by the %stack_overflow directive
  199.      */
  200.     public $overflow;
  201.     /**
  202.      * Line number for start of overflow code
  203.      * @var int 
  204.      */
  205.     public $overflowln;
  206.     /**
  207.      * Code to execute on parser failure
  208.      * 
  209.      * This is set by the %parse_failure directive
  210.      * @var string 
  211.      */
  212.     public $failure;
  213.     /**
  214.      * Line number for start of failure code
  215.      * @var int 
  216.      */
  217.     public $failureln;
  218.     /**
  219.      * Code to execute when the parser acccepts (completes parsing)
  220.      * 
  221.      * This is set by the %parse_accept directive
  222.      * @var string 
  223.      */
  224.     public $accept;
  225.     /**
  226.      * Line number for the start of accept code
  227.      * @var int 
  228.      */
  229.     public $acceptln;
  230.     /**
  231.      * Code appended to the generated file
  232.      * 
  233.      * This is set by the %code directive
  234.      * @var string 
  235.      */
  236.     public $extracode;
  237.     /**
  238.      * Line number for the start of the extra code
  239.      * @var int 
  240.      */
  241.     public $extracodeln;
  242.     /**
  243.      * Code to execute to destroy token data
  244.      * 
  245.      * This is set by the %token_destructor directive
  246.      * @var string 
  247.      */
  248.     public $tokendest;
  249.     /**
  250.      * Line number for token destroyer code
  251.      * @var int 
  252.      */
  253.     public $tokendestln;
  254.     /**
  255.      * Code for the default non-terminal destructor
  256.      * 
  257.      * This is set by the %default_destructor directive
  258.      * @var string 
  259.      */
  260.     public $vardest;
  261.     /**
  262.      * Line number for default non-terminal destructor code
  263.      * @var int 
  264.      */
  265.     public $vardestln;
  266.     /**
  267.      * Name of the input file
  268.      * @var string 
  269.      */
  270.     public $filename;
  271.     /**
  272.      * Name of the input file without its extension
  273.      * @var string 
  274.      */
  275.     public $filenosuffix;
  276.     /**
  277.      * Name of the current output file
  278.      * @var string 
  279.      */
  280.     public $outname;
  281.     /**
  282.      * A prefix added to token names
  283.      * @var string 
  284.      */
  285.     public $tokenprefix;
  286.     /**
  287.      * Number of parsing conflicts
  288.      * @var int 
  289.      */
  290.     public $nconflict;
  291.     /**
  292.      * Size of the parse tables
  293.      * @var int 
  294.      */
  295.     public $tablesize;
  296.     /**
  297.      * Public only basis configurations
  298.      */
  299.     public $basisflag;
  300.     /**
  301.      * True if any %fallback is seen in the grammer
  302.      * @var boolean 
  303.      */
  304.     public $has_fallback;
  305.     /**
  306.      * Name of the program
  307.      * @var string 
  308.      */
  309.     public $argv0;
  310.  
  311.     /* Find a precedence symbol of every rule in the grammar.
  312.      * 
  313.      * Those rules which have a precedence symbol coded in the input
  314.      * grammar using the "[symbol]" construct will already have the
  315.      * $rp->precsym field filled.  Other rules take as their precedence
  316.      * symbol the first RHS symbol with a defined precedence.  If there
  317.      * are not RHS symbols with a defined precedence, the precedence
  318.      * symbol field is left blank.
  319.      */
  320.     function FindRulePrecedences()
  321.     {
  322.         for ($rp $this->rule$rp$rp $rp->next{
  323.             if ($rp->precsym === 0{
  324.                 for ($i 0$i $rp->nrhs && $rp->precsym === 0$i++{
  325.                     $sp $rp->rhs[$i];
  326.                     if ($sp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL{
  327.                         for ($j 0$j $sp->nsubsym$j++{
  328.                             if ($sp->subsym[$j]->prec >= 0{
  329.                                 $rp->precsym $sp->subsym[$j];
  330.                                 break;
  331.                             }
  332.                         }
  333.                     elseif ($sp->prec >= 0{
  334.                         $rp->precsym $rp->rhs[$i];
  335.                     }
  336.                 }
  337.             }
  338.         }
  339.     }
  340.  
  341.     /**
  342.      * Find all nonterminals which will generate the empty string.
  343.      * Then go back and compute the first sets of every nonterminal.
  344.      * The first set is the set of all terminal symbols which can begin
  345.      * a string generated by that nonterminal.
  346.      */
  347.     function FindFirstSets()
  348.     {
  349.         for ($i 0$i $this->nsymbol$i++{
  350.             $this->symbols[$i]->lambda false;
  351.         }
  352.         for($i $this->nterminal$i $this->nsymbol$i++{
  353.             $this->symbols[$i]->firstset array();
  354.         }
  355.  
  356.         /* First compute all lambdas */
  357.         do{
  358.             $progress 0;
  359.             for ($rp $this->rule$rp$rp $rp->next{
  360.                 if ($rp->lhs->lambda{
  361.                     continue;
  362.                 }
  363.                 for ($i 0$i $rp->nrhs$i++{
  364.                     $sp $rp->rhs[$i];
  365.                     if ($sp->type != PHP_ParserGenerator_Symbol::TERMINAL || $sp->lambda === false{
  366.                         break;
  367.                     }
  368.                 }
  369.                 if ($i === $rp->nrhs{
  370.                     $rp->lhs->lambda true;
  371.                     $progress 1;
  372.                 }
  373.             }
  374.         while ($progress);
  375.  
  376.         /* Now compute all first sets */
  377.         do {
  378.             $progress 0;
  379.             for ($rp $this->rule$rp$rp $rp->next{
  380.                 $s1 $rp->lhs;
  381.                 for ($i 0$i $rp->nrhs$i++{
  382.                     $s2 $rp->rhs[$i];
  383.                     if ($s2->type == PHP_ParserGenerator_Symbol::TERMINAL{
  384.                         //progress += SetAdd(s1->firstset,s2->index);
  385.                         $progress += isset($s1->firstset[$s2->index]1;
  386.                         $s1->firstset[$s2->index1;
  387.                         break;
  388.                     elseif ($s2->type == PHP_ParserGenerator_Symbol::MULTITERMINAL{
  389.                         for ($j 0$j $s2->nsubsym$j++{
  390.                             //progress += SetAdd(s1->firstset,s2->subsym[j]->index);
  391.                             $progress += isset($s1->firstset[$s2->subsym[$j]->index]1;
  392.                             $s1->firstset[$s2->subsym[$j]->index1;
  393.                         }
  394.                         break;
  395.                     elseif ($s1 === $s2{
  396.                         if ($s1->lambda === false{
  397.                             break;
  398.                         }
  399.                     else {
  400.                         //progress += SetUnion(s1->firstset,s2->firstset);
  401.                         $test array_diff_key($s2->firstset$s1->firstset);
  402.                         if (count($test)) {
  403.                             $progress++;
  404.                             $s1->firstset += $test;
  405.                         }
  406.                         if ($s2->lambda === false{
  407.                             break;
  408.                         }
  409.                     }
  410.                 }
  411.             }
  412.         while ($progress);
  413.     }
  414.  
  415.     /**
  416.      * Compute all LR(0) states for the grammar.  Links
  417.      * are added to between some states so that the LR(1) follow sets
  418.      * can be computed later.
  419.      */
  420.     function FindStates()
  421.     {
  422.     
  423.         /* Find the start symbol */
  424.         if ($this->start{
  425.             $sp PHP_ParserGenerator_Symbol::Symbol_find($this->start);
  426.             if ($sp == 0{
  427.                 PHP_ParserGenerator::ErrorMsg($this->filename0,
  428.                     "The specified start symbol \"%s\" is not " .
  429.                     "in a nonterminal of the grammar.  \"%s\" will be used as the start " .
  430.                     "symbol instead."$this->start$this->rule->lhs->name);
  431.                 $this->errorcnt++;
  432.                 $sp $this->rule->lhs;
  433.             }
  434.         else {
  435.             $sp $this->rule->lhs;
  436.         }
  437.     
  438.         /* Make sure the start symbol doesn't occur on the right-hand side of
  439.         ** any rule.  Report an error if it does.  (YACC would generate a new
  440.         ** start symbol in this case.) */
  441.         for ($rp $this->rule$rp$rp $rp->next{
  442.             for ($i 0$i $rp->nrhs$i++{
  443.                 if ($rp->rhs[$i]->type == PHP_ParserGenerator_Symbol::MULTITERMINAL{
  444.                     foreach ($rp->rhs[$i]->subsym as $subsp{
  445.                         if ($subsp === $sp{
  446.                             PHP_ParserGenerator::ErrorMsg($this->filename0,
  447.                                 "The start symbol \"%s\" occurs on the " .
  448.                                 "right-hand side of a rule. This will result in a parser which " .
  449.                                 "does not work properly."$sp->name);
  450.                             $this->errorcnt++;
  451.                         }
  452.                     }
  453.                 elseif ($rp->rhs[$i=== $sp{
  454.                     PHP_ParserGenerator::ErrorMsg($this->filename0,
  455.                         "The start symbol \"%s\" occurs on the " .
  456.                         "right-hand side of a rule. This will result in a parser which " .
  457.                         "does not work properly."$sp->name);
  458.                     $this->errorcnt++;
  459.                 }
  460.             }
  461.         }
  462.     
  463.         /* The basis configuration set for the first state
  464.         ** is all rules which have the start symbol as their
  465.         ** left-hand side */
  466.         for ($rp $sp->rule$rp$rp $rp->nextlhs{
  467.             $newcfp PHP_ParserGenerator_Config::Configlist_addbasis($rp0);
  468.             $newcfp->fws[01;
  469.         }
  470.     
  471.         /* Compute the first state.  All other states will be
  472.         ** computed automatically during the computation of the first one.
  473.         ** The returned pointer to the first state is not used. */
  474.         $newstp array();
  475.         $newstp $this->getstate();
  476.         if (is_array($newstp)) {
  477.             $this->buildshifts($newstp[0])/* Recursively compute successor states */
  478.         }
  479.     }
  480.  
  481.     /**
  482.      * @return PHP_ParserGenerator_State 
  483.      */
  484.     private function getstate()
  485.     {
  486.         /* Extract the sorted basis of the new state.  The basis was constructed
  487.         ** by prior calls to "Configlist_addbasis()". */
  488.         $bp PHP_ParserGenerator_Config::Configlist_basis();
  489.     
  490.         /* Get a state with the same basis */
  491.         $stp PHP_ParserGenerator_State::State_find($bp);
  492.         if ($stp{
  493.             /* A state with the same basis already exists!  Copy all the follow-set
  494.             ** propagation links from the state under construction into the
  495.             ** preexisting state, then return a pointer to the preexisting state */
  496.             for($x $bp$y $stp->bp$x && $y$x $x->bp$y $y->bp{
  497.                 PHP_ParserGenerator_PropagationLink::Plink_copy($y->bplp$x->bplp);
  498.                 PHP_ParserGenerator_PropagationLink::Plink_delete($x->fplp);
  499.                 $x->fplp $x->bplp 0;
  500.             }
  501.             $cfp PHP_ParserGenerator_Config::Configlist_return();
  502.             PHP_ParserGenerator_Config::Configlist_eat($cfp);
  503.         else {
  504.             /* This really is a new state.  Construct all the details */
  505.             PHP_ParserGenerator_Config::Configlist_closure($this);    /* Compute the configuration closure */
  506.             PHP_ParserGenerator_Config::Configlist_sort();           /* Sort the configuration closure */
  507.             $cfp PHP_ParserGenerator_Config::Configlist_return();   /* Get a pointer to the config list */
  508.             $stp new PHP_ParserGenerator_State;           /* A new state structure */
  509.             $stp->bp $bp;                /* Remember the configuration basis */
  510.             $stp->cfp $cfp;              /* Remember the configuration closure */
  511.             $stp->statenum $this->nstate++/* Every state gets a sequence number */
  512.             $stp->ap 0;                 /* No actions, yet. */
  513.             PHP_ParserGenerator_State::State_insert($stp$stp->bp);   /* Add to the state table */
  514.             // this can't work, recursion is too deep, move it into FindStates()
  515.             //$this->buildshifts($stp);       /* Recursively compute successor states */
  516.             return array($stp);
  517.         }
  518.         return $stp;
  519.     }
  520.  
  521.     /**
  522.      * Construct all successor states to the given state.  A "successor"
  523.      * state is any state which can be reached by a shift action.
  524.      * @param PHP_ParserGenerator_Data 
  525.      * @param PHP_ParserGenerator_State The state from which successors are computed
  526.      */
  527.     private function buildshifts(PHP_ParserGenerator_State $stp)
  528.     {
  529. //    struct config *cfp;  /* For looping thru the config closure of "stp" */
  530. //    struct config *bcfp; /* For the inner loop on config closure of "stp" */
  531. //    struct config *new;  /* */
  532. //    struct symbol *sp;   /* Symbol following the dot in configuration "cfp" */
  533. //    struct symbol *bsp;  /* Symbol following the dot in configuration "bcfp" */
  534. //    struct state *newstp; /* A pointer to a successor state */
  535.     
  536.         /* Each configuration becomes complete after it contibutes to a successor
  537.         ** state.  Initially, all configurations are incomplete */
  538.         $cfp $stp->cfp;
  539.         for ($cfp $stp->cfp$cfp$cfp $cfp->next{
  540.             $cfp->status PHP_ParserGenerator_Config::INCOMPLETE;
  541.         }
  542.     
  543.         /* Loop through all configurations of the state "stp" */
  544.         for ($cfp $stp->cfp$cfp$cfp $cfp->next{
  545.             if ($cfp->status == PHP_ParserGenerator_Config::COMPLETE{
  546.                 continue;    /* Already used by inner loop */
  547.             }
  548.             if ($cfp->dot >= $cfp->rp->nrhs{
  549.                 continue;  /* Can't shift this config */
  550.             }
  551.             PHP_ParserGenerator_Config::Configlist_reset();                      /* Reset the new config set */
  552.             $sp $cfp->rp->rhs[$cfp->dot];             /* Symbol after the dot */
  553.     
  554.             /* For every configuration in the state "stp" which has the symbol "sp"
  555.             ** following its dot, add the same configuration to the basis set under
  556.             ** construction but with the dot shifted one symbol to the right. */
  557.             $bcfp $cfp;
  558.             for ($bcfp $cfp$bcfp$bcfp $bcfp->next{
  559.                 if ($bcfp->status == PHP_ParserGenerator_Config::COMPLETE{
  560.                     continue;    /* Already used */
  561.                 }
  562.                 if ($bcfp->dot >= $bcfp->rp->nrhs{
  563.                     continue/* Can't shift this one */
  564.                 }
  565.                 $bsp $bcfp->rp->rhs[$bcfp->dot];           /* Get symbol after dot */
  566.                 if (!PHP_ParserGenerator_Symbol::same_symbol($bsp$sp)) {
  567.                     continue;      /* Must be same as for "cfp" */
  568.                 }
  569.                 $bcfp->status PHP_ParserGenerator_Config::COMPLETE;             /* Mark this config as used */
  570.                 $new PHP_ParserGenerator_Config::Configlist_addbasis($bcfp->rp$bcfp->dot 1);
  571.                 PHP_ParserGenerator_PropagationLink::Plink_add($new->bplp$bcfp);
  572.             }
  573.  
  574.             /* Get a pointer to the state described by the basis configuration set
  575.             ** constructed in the preceding loop */
  576.             $newstp $this->getstate();
  577.             if (is_array($newstp)) {
  578.                 $this->buildshifts($newstp[0])/* Recursively compute successor states */
  579.                 $newstp $newstp[0];
  580.             }
  581.  
  582.             /* The state "newstp" is reached from the state "stp" by a shift action
  583.             ** on the symbol "sp" */
  584.             if ($sp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL{
  585.                 for($i 0$i $sp->nsubsym$i++{
  586.                     PHP_ParserGenerator_Action::Action_add($stp->apPHP_ParserGenerator_Action::SHIFT$sp->subsym[$i],
  587.                                             $newstp);
  588.                 }
  589.             else {
  590.                 PHP_ParserGenerator_Action::Action_add($stp->apPHP_ParserGenerator_Action::SHIFT$sp$newstp);
  591.             }
  592.         }
  593.     }
  594.  
  595.     /**
  596.      * Construct the propagation links
  597.      */
  598.     function FindLinks()
  599.     {
  600.         /* Housekeeping detail:
  601.         ** Add to every propagate link a pointer back to the state to
  602.         ** which the link is attached. */
  603.         foreach ($this->sorted as $info{
  604.             $info->key->stp $info->data;
  605.         }
  606.         
  607.         /* Convert all backlinks into forward links.  Only the forward
  608.         ** links are used in the follow-set computation. */
  609.         for ($i 0$i $this->nstate$i++{
  610.             $stp $this->sorted[$i];
  611.             for ($cfp $stp->data->cfp$cfp$cfp $cfp->next{
  612.                 for ($plp $cfp->bplp$plp$plp $plp->next{
  613.                     $other $plp->cfp;
  614.                     PHP_ParserGenerator_PropagationLink::Plink_add($other->fplp$cfp);
  615.                 }
  616.             }
  617.         }
  618.     }
  619.  
  620.     /**
  621.      * Compute the reduce actions, and resolve conflicts.
  622.      */
  623.     function FindActions()
  624.     {
  625.         /* Add all of the reduce actions 
  626.         ** A reduce action is added for each element of the followset of
  627.         ** a configuration which has its dot at the extreme right.
  628.         */
  629.         for ($i 0$i $this->nstate$i++{   /* Loop over all states */
  630.             $stp $this->sorted[$i]->data;
  631.             for ($cfp $stp->cfp$cfp$cfp $cfp->next{
  632.                 /* Loop over all configurations */
  633.                 if ($cfp->rp->nrhs == $cfp->dot{        /* Is dot at extreme right? */
  634.                     for ($j 0$j $this->nterminal$j++{
  635.                         if (isset($cfp->fws[$j])) {
  636.                             /* Add a reduce action to the state "stp" which will reduce by the
  637.                             ** rule "cfp->rp" if the lookahead symbol is "$this->symbols[j]" */
  638.                             PHP_ParserGenerator_Action::Action_add($stp->apPHP_ParserGenerator_Action::REDUCE,
  639.                                                     $this->symbols[$j]$cfp->rp);
  640.                         }
  641.                     }
  642.                 }
  643.             }
  644.         }
  645.  
  646.         /* Add the accepting token */
  647.         if ($this->start instanceof PHP_ParserGenerator_Symbol{
  648.             $sp PHP_ParserGenerator_Symbol::Symbol_find($this->start);
  649.             if ($sp === 0{
  650.                 $sp $this->rule->lhs;
  651.             }
  652.         else {
  653.             $sp $this->rule->lhs;
  654.         }
  655.         /* Add to the first state (which is always the starting state of the
  656.         ** finite state machine) an action to ACCEPT if the lookahead is the
  657.         ** start nonterminal.  */
  658.         PHP_ParserGenerator_Action::Action_add($this->sorted[0]->data->apPHP_ParserGenerator_Action::ACCEPT$sp0);
  659.     
  660.         /* Resolve conflicts */
  661.         for ($i 0$i $this->nstate$i++{
  662.     //    struct action *ap, *nap;
  663.     //    struct state *stp;
  664.             $stp $this->sorted[$i]->data;
  665.             if (!$stp->ap{
  666.                 throw new Exception('state has no actions associated');
  667.             }
  668.             $stp->ap PHP_ParserGenerator_Action::Action_sort($stp->ap);
  669.             for ($ap $stp->ap$ap !== && $ap->next !== 0$ap $ap->next{
  670.                 for ($nap $ap->next$nap !== && $nap->sp === $ap->sp $nap $nap->next{
  671.                     /* The two actions "ap" and "nap" have the same lookahead.
  672.                     ** Figure out which one should be used */
  673.                     $this->nconflict += $this->resolve_conflict($ap$nap$this->errsym);
  674.                 }
  675.             }
  676.         }
  677.     
  678.         /* Report an error for each rule that can never be reduced. */
  679.         for ($rp $this->rule$rp$rp $rp->next{
  680.             $rp->canReduce false;
  681.         }
  682.         for ($i 0$i $this->nstate$i++{
  683.             for ($ap $this->sorted[$i]->data->ap$ap !== 0$ap $ap->next{
  684.                 if ($ap->type == PHP_ParserGenerator_Action::REDUCE{
  685.                     $ap->x->canReduce true;
  686.                 }
  687.             }
  688.         }
  689.         for ($rp $this->rule$rp !== 0$rp $rp->next{
  690.             if ($rp->canReduce{
  691.                 continue;
  692.             }
  693.             PHP_ParserGenerator::ErrorMsg($this->filename$rp->ruleline"This rule can not be reduced (is not connected to the start symbol).\n");
  694.             $this->errorcnt++;
  695.         }
  696.     }
  697.  
  698.     /** Resolve a conflict between the two given actions.  If the
  699.      * conflict can't be resolve, return non-zero.
  700.      *
  701.      * NO LONGER TRUE:
  702.      *   To resolve a conflict, first look to see if either action
  703.      *   is on an error rule.  In that case, take the action which
  704.      *   is not associated with the error rule.  If neither or both
  705.      *   actions are associated with an error rule, then try to
  706.      *   use precedence to resolve the conflict.
  707.      *
  708.      * If either action is a SHIFT, then it must be apx.  This
  709.      * function won't work if apx->type==REDUCE and apy->type==SHIFT.
  710.      * @param PHP_ParserGenerator_Action 
  711.      * @param PHP_ParserGenerator_Action 
  712.      * @param PHP_ParserGenerator_Symbol|nullThe error symbol (if defined.  NULL otherwise)
  713.      */
  714.     function resolve_conflict($apx$apy$errsym)
  715.     {
  716.         $errcnt 0;
  717.         if ($apx->sp !== $apy->sp{
  718.             throw new Exception('no conflict but resolve_conflict called');
  719.         }
  720.         if ($apx->type == PHP_ParserGenerator_Action::SHIFT && $apy->type == PHP_ParserGenerator_Action::REDUCE{
  721.             $spx $apx->sp;
  722.             $spy $apy->x->precsym;
  723.             if ($spy === || $spx->prec || $spy->prec 0{
  724.                 /* Not enough precedence information. */
  725.                 $apy->type PHP_ParserGenerator_Action::CONFLICT;
  726.                 $errcnt++;
  727.             elseif ($spx->prec $spy->prec{    /* Lower precedence wins */
  728.                 $apy->type PHP_ParserGenerator_Action::RD_RESOLVED;
  729.             elseif ($spx->prec $spy->prec{
  730.                 $apx->type PHP_ParserGenerator_Action::SH_RESOLVED;
  731.             elseif ($spx->prec === $spy->prec && $spx->assoc == PHP_ParserGenerator_Symbol::RIGHT{
  732.                 /* Use operator */
  733.                 $apy->type PHP_ParserGenerator_Action::RD_RESOLVED;                       /* associativity */
  734.             elseif ($spx->prec === $spy->prec && $spx->assoc == PHP_ParserGenerator_Symbol::LEFT{
  735.                 /* to break tie */
  736.                 $apx->type PHP_ParserGenerator_Action::SH_RESOLVED;
  737.             else {
  738.                 if ($spx->prec !== $spy->prec || $spx->assoc !== PHP_ParserGenerator_Symbol::NONE{
  739.                     throw new Exception('$spx->prec !== $spy->prec || $spx->assoc !== PHP_ParserGenerator_Symbol::NONE');
  740.                 }
  741.                 $apy->type PHP_ParserGenerator_Action::CONFLICT;
  742.                 $errcnt++;
  743.             }
  744.         elseif ($apx->type == PHP_ParserGenerator_Action::REDUCE && $apy->type == PHP_ParserGenerator_Action::REDUCE{
  745.             $spx $apx->x->precsym;
  746.             $spy $apy->x->precsym;
  747.             if ($spx === || $spy === || $spx->prec ||
  748.                   $spy->prec || $spx->prec === $spy->prec{
  749.                 $apy->type PHP_ParserGenerator_Action::CONFLICT;
  750.                 $errcnt++;
  751.             elseif ($spx->prec $spy->prec{
  752.                 $apy->type PHP_ParserGenerator_Action::RD_RESOLVED;
  753.             elseif ($spx->prec $spy->prec{
  754.                 $apx->type PHP_ParserGenerator_Action::RD_RESOLVED;
  755.             }
  756.         else {
  757.             if ($apx->type!== PHP_ParserGenerator_Action::SH_RESOLVED &&
  758.                 $apx->type!== PHP_ParserGenerator_Action::RD_RESOLVED &&
  759.                 $apx->type!== PHP_ParserGenerator_Action::CONFLICT &&
  760.                 $apy->type!== PHP_ParserGenerator_Action::SH_RESOLVED &&
  761.                 $apy->type!== PHP_ParserGenerator_Action::RD_RESOLVED &&
  762.                 $apy->type!== PHP_ParserGenerator_Action::CONFLICT{
  763.                 throw new Exception('$apx->type!== PHP_ParserGenerator_Action::SH_RESOLVED &&
  764.                 $apx->type!== PHP_ParserGenerator_Action::RD_RESOLVED &&
  765.                 $apx->type!== PHP_ParserGenerator_Action::CONFLICT &&
  766.                 $apy->type!== PHP_ParserGenerator_Action::SH_RESOLVED &&
  767.                 $apy->type!== PHP_ParserGenerator_Action::RD_RESOLVED &&
  768.                 $apy->type!== PHP_ParserGenerator_Action::CONFLICT');
  769.             }
  770.             /* The REDUCE/SHIFT case cannot happen because SHIFTs come before
  771.             ** REDUCEs on the list.  If we reach this point it must be because
  772.             ** the parser conflict had already been resolved. */
  773.         }
  774.         return $errcnt;
  775.     }
  776.  
  777.     /**
  778.      * Reduce the size of the action tables, if possible, by making use
  779.      * of defaults.
  780.      *
  781.      * In this version, we take the most frequent REDUCE action and make
  782.      * it the default.
  783.      */
  784.     function CompressTables()
  785.     {
  786.         for ($i 0$i $this->nstate$i++{
  787.             $stp $this->sorted[$i]->data;
  788.             $nbest 0;
  789.             $rbest 0;
  790.  
  791.             for ($ap $stp->ap$ap$ap $ap->next{
  792.                 if ($ap->type != PHP_ParserGenerator_Action::REDUCE{
  793.                     continue;
  794.                 }
  795.                 $rp $ap->x;
  796.                 if ($rp === $rbest{
  797.                     continue;
  798.                 }
  799.                 $n 1;
  800.                 for ($ap2 $ap->next$ap2$ap2 $ap2->next{
  801.                     if ($ap2->type != PHP_ParserGenerator_Action::REDUCE{
  802.                         continue;
  803.                     }
  804.                     $rp2 $ap2->x;
  805.                     if ($rp2 === $rbest{
  806.                         continue;
  807.                     }
  808.                     if ($rp2 === $rp{
  809.                         $n++;
  810.                     }
  811.                 }
  812.                 if ($n $nbest{
  813.                     $nbest $n;
  814.                     $rbest $rp;
  815.                 }
  816.             }
  817.  
  818.             /* Do not make a default if the number of rules to default
  819.             ** is not at least 1 */
  820.             if ($nbest 1{
  821.                 continue;
  822.             }
  823.  
  824.  
  825.             /* Combine matching REDUCE actions into a single default */
  826.             for ($ap $stp->ap$ap$ap $ap->next{
  827.                 if ($ap->type == PHP_ParserGenerator_Action::REDUCE && $ap->=== $rbest{
  828.                     break;
  829.                 }
  830.             }
  831.             if ($ap === 0{
  832.                 throw new Exception('$ap is not an object');
  833.             }
  834.             $ap->sp PHP_ParserGenerator_Symbol::Symbol_new("{default}");
  835.             for ($ap $ap->next$ap$ap $ap->next{
  836.                 if ($ap->type == PHP_ParserGenerator_Action::REDUCE && $ap->=== $rbest{
  837.                     $ap->type PHP_ParserGenerator_Action::NOT_USED;
  838.                 }
  839.             }
  840.             $stp->ap PHP_ParserGenerator_Action::Action_sort($stp->ap);
  841.         }
  842.     }
  843.  
  844.     /**
  845.      * Renumber and resort states so that states with fewer choices
  846.      * occur at the end.  Except, keep state 0 as the first state.
  847.      */
  848.     function ResortStates()
  849.     {
  850.         for ($i 0$i $this->nstate$i++{
  851.             $stp $this->sorted[$i]->data;
  852.             $stp->nTknAct $stp->nNtAct 0;
  853.             $stp->iDflt $this->nstate + $this->nrule;
  854.             $stp->iTknOfst PHP_ParserGenerator_Data::NO_OFFSET;
  855.             $stp->iNtOfst PHP_ParserGenerator_Data::NO_OFFSET;
  856.             for ($ap $stp->ap$ap$ap $ap->next{
  857.                 if ($this->compute_action($ap>= 0{
  858.                     if ($ap->sp->index $this->nterminal{
  859.                         $stp->nTknAct++;
  860.                     elseif ($ap->sp->index $this->nsymbol{
  861.                         $stp->nNtAct++;
  862.                     else {
  863.                         $stp->iDflt $this->compute_action($ap);
  864.                     }
  865.                 }
  866.             }
  867.             $this->sorted[$i$stp;
  868.         }
  869.         $save $this->sorted[0];
  870.         unset($this->sorted[0]);
  871.         usort($this->sortedarray('PHP_ParserGenerator_State''stateResortCompare'));
  872.         array_unshift($this->sorted$save);
  873.         for($i 0$i $this->nstate$i++{
  874.             $this->sorted[$i]->statenum $i;
  875.         }
  876.     }
  877.  
  878.     /**
  879.      * Given an action, compute the integer value for that action
  880.      * which is to be put in the action table of the generated machine.
  881.      * Return negative if no action should be generated.
  882.      * @param PHP_ParserGenerator_Action 
  883.      */
  884.     function compute_action($ap)
  885.     {
  886.         switch ($ap->type{
  887.             case PHP_ParserGenerator_Action::SHIFT:
  888.                 $act $ap->x->statenum;
  889.                 break;
  890.             case PHP_ParserGenerator_Action::REDUCE:
  891.                 $act $ap->x->index $this->nstate;
  892.                 break;
  893.             case PHP_ParserGenerator_Action::ERROR:
  894.                 $act $this->nstate + $this->nrule;
  895.                 break;
  896.             case PHP_ParserGenerator_Action::ACCEPT:
  897.                 $act $this->nstate + $this->nrule + 1;
  898.                 break;
  899.             default:
  900.                 $act = -1;
  901.                 break;
  902.         }
  903.         return $act;
  904.     }
  905.  
  906.     /**
  907.      * Generate the "Parse.out" log file
  908.      */
  909.     function ReportOutput()
  910.     {
  911.         $fp fopen($this->filenosuffix . ".out""wb");
  912.         if (!$fp{
  913.             return;
  914.         }
  915.         for ($i 0$i $this->nstate$i++{
  916.             $stp $this->sorted[$i];
  917.             fprintf($fp"State %d:\n"$stp->statenum);
  918.             if ($this->basisflag{
  919.                 $cfp $stp->bp;
  920.             else {
  921.                 $cfp $stp->cfp;
  922.             }
  923.             while ($cfp{
  924.                 if ($cfp->dot == $cfp->rp->nrhs{
  925.                     $buf sprintf('(%d)'$cfp->rp->index);
  926.                     fprintf($fp'    %5s '$buf);
  927.                 else {
  928.                     fwrite($fp,'          ');
  929.                 }
  930.                 $cfp->ConfigPrint($fp);
  931.                 fwrite($fp"\n");
  932.                 if (0{
  933.                     //SetPrint(fp,cfp->fws,$this);
  934.                     //PlinkPrint(fp,cfp->fplp,"To  ");
  935.                     //PlinkPrint(fp,cfp->bplp,"From");
  936.                 }
  937.                 if ($this->basisflag{
  938.                     $cfp $cfp->bp;
  939.                 else {
  940.                     $cfp $cfp->next;
  941.                 }
  942.             }
  943.             fwrite($fp"\n");
  944.             for ($ap $stp->ap$ap$ap $ap->next{
  945.                 if ($ap->PrintAction($fp30)) {
  946.                     fprintf($fp,"\n");
  947.                 }
  948.             }
  949.             fwrite($fp,"\n");
  950.         }
  951.         fclose($fp);
  952.     }
  953.  
  954.     /**
  955.      * The next function finds the template file and opens it, returning
  956.      * a pointer to the opened file.
  957.      * @return resource 
  958.      */
  959.     private function tplt_open()
  960.     {
  961.         $templatename dirname(dirname(__FILE__)) DIRECTORY_SEPARATOR "Lempar.php";
  962.         $buf $this->filenosuffix . '.lt';
  963.         if (file_exists($buf&& is_readable($buf)) {
  964.             $tpltname $buf;
  965.         elseif (file_exists($templatename&& is_readable($templatename)) {
  966.             $tpltname $templatename;
  967.         elseif ($fp @fopen($templatename'rb'true)) {
  968.             return $fp;
  969.         }
  970.         if (!isset($tpltname)) {
  971.             echo "Can't find the parser driver template file \"%s\".\n",
  972.                 $templatename;
  973.             $this->errorcnt++;
  974.             return 0;
  975.         }
  976.         $in @fopen($tpltname,"rb");
  977.         if (!$in{
  978.             printf("Can't open the template file \"%s\".\n"$tpltname);
  979.             $this->errorcnt++;
  980.             return 0;
  981.         }
  982.         return $in;
  983.     }
  984.  
  985. #define LINESIZE 1000
  986.     
  987.     /**#@+
  988.      * The next cluster of routines are for reading the template file
  989.      * and writing the results to the generated parser
  990.      */
  991.     /**
  992.      * The first function transfers data from "in" to "out" until
  993.      * a line is seen which begins with "%%".  The line number is
  994.      * tracked.
  995.      *
  996.      * if name!=0, then any word that begin with "Parse" is changed to
  997.      * begin with *name instead.
  998.      */
  999.     private function tplt_xfer($name$in$out&$lineno)
  1000.     {
  1001.         while (($line fgets($in1024)) && ($line[0!= '%' || $line[1!= '%')) {
  1002.             $lineno++;
  1003.             $iStart 0;
  1004.             if ($name{
  1005.                 for ($i 0$i strlen($line)$i++{
  1006.                     if ($line[$i== 'P' && substr($line$i5== "Parse"
  1007.                           && ($i === || preg_match('/[^a-zA-Z]/'$line[$i 1]))) {
  1008.                         if ($i $iStart{
  1009.                             fwrite($outsubstr($line$iStart$i $iStart));
  1010.                         }
  1011.                         fwrite($out$name);
  1012.                         $i += 4;
  1013.                         $iStart $i 1;
  1014.                     }
  1015.                 }
  1016.             }
  1017.             fwrite($outsubstr($line$iStart));
  1018.         }
  1019.     }
  1020.  
  1021.     /**
  1022.      * Print a #line directive line to the output file.
  1023.      */
  1024.     private function tplt_linedir($out$lineno$filename)
  1025.     {
  1026.         fwrite($out'#line ' $lineno ' "' $filename "\"\n");
  1027.     }
  1028.  
  1029.     /**
  1030.      * Print a string to the file and keep the linenumber up to date
  1031.      */
  1032.     private function tplt_print($out$str$strln&$lineno)
  1033.     {
  1034.         if ($str == ''{
  1035.             return;
  1036.         }
  1037.         $this->tplt_linedir($out$strln$this->filename);
  1038.         $lineno++;
  1039.         fwrite($out$str);
  1040.         $lineno += count(explode("\n"$str)) 1;
  1041.         $this->tplt_linedir($out$lineno 2$this->outname);
  1042.         $lineno += 2;
  1043.     }
  1044.     /**#@-*/
  1045.  
  1046.     /**
  1047.      * Compute all followsets.
  1048.      *
  1049.      * A followset is the set of all symbols which can come immediately
  1050.      * after a configuration.
  1051.      */
  1052.     function FindFollowSets()
  1053.     {
  1054.         for ($i 0$i $this->nstate$i++{
  1055.             for ($cfp $this->sorted[$i]->data->cfp$cfp$cfp $cfp->next{
  1056.                 $cfp->status PHP_ParserGenerator_Config::INCOMPLETE;
  1057.             }
  1058.         }
  1059.         
  1060.         do {
  1061.             $progress 0;
  1062.             for ($i 0$i $this->nstate$i++{
  1063.                 for ($cfp $this->sorted[$i]->data->cfp$cfp$cfp $cfp->next{
  1064.                     if ($cfp->status == PHP_ParserGenerator_Config::COMPLETE{
  1065.                         continue;
  1066.                     }
  1067.                     for ($plp $cfp->fplp$plp$plp $plp->next{
  1068.                         $a array_diff_key($cfp->fws$plp->cfp->fws);
  1069.                         if (count($a)) {
  1070.                             $plp->cfp->fws += $a;
  1071.                             $plp->cfp->status PHP_ParserGenerator_Config::INCOMPLETE;
  1072.                             $progress 1;
  1073.                         }
  1074.                     }
  1075.                     $cfp->status PHP_ParserGenerator_Config::COMPLETE;
  1076.                 }
  1077.             }
  1078.         while ($progress);
  1079.     }
  1080.  
  1081.     /**
  1082.      * Generate C source code for the parser
  1083.      * @param int Output in makeheaders format if true
  1084.      */
  1085.     function ReportTable($mhflag)
  1086.     {
  1087. //        FILE *out, *in;
  1088. //        char line[LINESIZE];
  1089. //        int  lineno;
  1090. //        struct state *stp;
  1091. //        struct action *ap;
  1092. //        struct rule *rp;
  1093. //        struct acttab *pActtab;
  1094. //        int i, j, n;
  1095. //        char *name;
  1096. //        int mnTknOfst, mxTknOfst;
  1097. //        int mnNtOfst, mxNtOfst;
  1098. //        struct axset *ax;
  1099.         
  1100.         $in $this->tplt_open();
  1101.         if (!$in{
  1102.             return;
  1103.         }
  1104.         $out fopen($this->filenosuffix . ".php""wb");
  1105.         if (!$out{
  1106.             fclose($in);
  1107.             return;
  1108.         }
  1109.         $this->outname = $this->filenosuffix . ".php";
  1110.         $lineno 1;
  1111.         $this->tplt_xfer($this->name$in$out$lineno);
  1112.         
  1113.         /* Generate the include code, if any */
  1114.         $this->tplt_print($out$this->include_code$this->includeln$lineno);
  1115.         $this->tplt_xfer($this->name$in$out$lineno);
  1116.  
  1117.         /* Generate the class declaration code */
  1118.         $this->tplt_print($out$this->declare_classcode$this->declare_classln,
  1119.             $lineno);
  1120.         $this->tplt_xfer($this->name$in$out$lineno);
  1121.  
  1122.         /* Generate the internal parser class include code, if any */
  1123.         $this->tplt_print($out$this->include_classcode$this->include_classln,
  1124.             $lineno);
  1125.         $this->tplt_xfer($this->name$in$out$lineno);
  1126.  
  1127.         /* Generate #defines for all tokens */
  1128.         //if ($mhflag) {
  1129.             //fprintf($out, "#if INTERFACE\n");
  1130.             $lineno++;
  1131.             if ($this->tokenprefix{
  1132.                 $prefix $this->tokenprefix;
  1133.             else {
  1134.                 $prefix '';
  1135.             }
  1136.             for ($i 1$i $this->nterminal$i++{
  1137.                 fprintf($out"    const %s%-30s = %2d;\n"$prefix$this->symbols[$i]->name$i);
  1138.                 $lineno++;
  1139.             }
  1140.             //fwrite($out, "#endif\n");
  1141.             $lineno++;
  1142.         //}
  1143.         fwrite($out"    const YY_NO_ACTION = " .
  1144.             ($this->nstate + $this->nrule + 2";\n");
  1145.         $lineno++;
  1146.         fwrite($out"    const YY_ACCEPT_ACTION = " .
  1147.             ($this->nstate + $this->nrule + 1";\n");
  1148.         $lineno++;
  1149.         fwrite($out"    const YY_ERROR_ACTION = " .
  1150.             ($this->nstate + $this->nrule";\n");
  1151.         $lineno++;
  1152.         $this->tplt_xfer($this->name$in$out$lineno);
  1153.         
  1154.         /* Generate the action table and its associates:
  1155.         **
  1156.         **  yy_action[]        A single table containing all actions.
  1157.         **  yy_lookahead[]     A table containing the lookahead for each entry in
  1158.         **                     yy_action.  Used to detect hash collisions.
  1159.         **  yy_shift_ofst[]    For each state, the offset into yy_action for
  1160.         **                     shifting terminals.
  1161.         **  yy_reduce_ofst[]   For each state, the offset into yy_action for
  1162.         **                     shifting non-terminals after a reduce.
  1163.         **  yy_default[]       Default action for each state.
  1164.         */
  1165.  
  1166.         /* Compute the actions on all states and count them up */
  1167.  
  1168.         $ax array();
  1169.         for ($i 0$i $this->nstate$i++{
  1170.             $stp $this->sorted[$i];
  1171.             $ax[$i 2array();
  1172.             $ax[$i 2]['stp'$stp;
  1173.             $ax[$i 2]['isTkn'1;
  1174.             $ax[$i 2]['nAction'$stp->nTknAct;
  1175.             $ax[$i 1array();
  1176.             $ax[$i 1]['stp'$stp;
  1177.             $ax[$i 1]['isTkn'0;
  1178.             $ax[$i 1]['nAction'$stp->nNtAct;
  1179.         }
  1180.         $mxTknOfst $mnTknOfst 0;
  1181.         $mxNtOfst $mnNtOfst 0;
  1182.  
  1183.         /* Compute the action table.  In order to try to keep the size of the
  1184.         ** action table to a minimum, the heuristic of placing the largest action
  1185.         ** sets first is used.
  1186.         */
  1187.  
  1188.         usort($axarray('PHP_ParserGenerator_Data''axset_compare'));
  1189.         $pActtab new PHP_ParserGenerator_ActionTable;
  1190.         for ($i 0$i $this->nstate * && $ax[$i]['nAction'0$i++{
  1191.             $stp $ax[$i]['stp'];
  1192.             if ($ax[$i]['isTkn']{
  1193.                 for ($ap $stp->ap$ap$ap $ap->next{
  1194.                     if ($ap->sp->index >= $this->nterminal{
  1195.                         continue;
  1196.                     }
  1197.                     $action $this->compute_action($ap);
  1198.                     if ($action 0{
  1199.                         continue;
  1200.                     }
  1201.                     $pActtab->acttab_action($ap->sp->index$action);
  1202.                 }
  1203.                 $stp->iTknOfst $pActtab->acttab_insert();
  1204.                 if ($stp->iTknOfst $mnTknOfst{
  1205.                     $mnTknOfst $stp->iTknOfst;
  1206.                 }
  1207.                 if ($stp->iTknOfst $mxTknOfst{
  1208.                     $mxTknOfst $stp->iTknOfst;
  1209.                 }
  1210.             else {
  1211.                 for ($ap $stp->ap$ap$ap $ap->next{
  1212.                     if ($ap->sp->index $this->nterminal{
  1213.                         continue;
  1214.                     }
  1215.                     if ($ap->sp->index == $this->nsymbol{
  1216.                         continue;
  1217.                     }
  1218.                     $action $this->compute_action($ap);
  1219.                     if ($action 0{
  1220.                         continue;
  1221.                     }
  1222.                     $pActtab->acttab_action($ap->sp->index$action);
  1223.                 }
  1224.                 $stp->iNtOfst $pActtab->acttab_insert();
  1225.                 if ($stp->iNtOfst $mnNtOfst{
  1226.                     $mnNtOfst $stp->iNtOfst;
  1227.                 }
  1228.                 if ($stp->iNtOfst $mxNtOfst{
  1229.                     $mxNtOfst $stp->iNtOfst;
  1230.                 }
  1231.             }
  1232.         }
  1233.         /* Output the yy_action table */
  1234.  
  1235.         fprintf($out"    const YY_SZ_ACTTAB = %d;\n"$pActtab->nAction);
  1236.         $lineno++;
  1237.         fwrite($out"static public \$yy_action = array(\n");
  1238.         $lineno++;
  1239.         $n $pActtab->nAction;
  1240.         for($i $j 0$i $n$i++{
  1241.             $action $pActtab->aAction[$i]['action'];
  1242.             if ($action 0{
  1243.                 $action $this->nsymbol + $this->nrule + 2;
  1244.             }
  1245.             // change next line
  1246.             if ($j === 0{
  1247.                 fprintf($out" /* %5d */ "$i);
  1248.             }
  1249.             fprintf($out" %4d,"$action);
  1250.             if ($j == || $i == $n 1{
  1251.                 fwrite($out"\n");
  1252.                 $lineno++;
  1253.                 $j 0;
  1254.             else {
  1255.                 $j++;
  1256.             }
  1257.         }
  1258.         fwrite($out"    );\n")$lineno++;
  1259.  
  1260.         /* Output the yy_lookahead table */
  1261.  
  1262.         fwrite($out"    static public \$yy_lookahead = array(\n");
  1263.         $lineno++;
  1264.         for ($i $j 0$i $n$i++{
  1265.             $la $pActtab->aAction[$i]['lookahead'];
  1266.             if ($la 0{
  1267.                 $la $this->nsymbol;
  1268.             }
  1269.             // change next line
  1270.             if ($j === 0{
  1271.                 fprintf($out" /* %5d */ "$i);
  1272.             }
  1273.             fprintf($out" %4d,"$la);
  1274.             if ($j == || $i == $n 1{
  1275.                 fwrite($out"\n");
  1276.                 $lineno++;
  1277.                 $j 0;
  1278.             else {
  1279.                 $j++;
  1280.             }
  1281.         }
  1282.         fwrite($out");\n");
  1283.         $lineno++;
  1284.  
  1285.         /* Output the yy_shift_ofst[] table */
  1286.         fprintf($out"    const YY_SHIFT_USE_DFLT = %d;\n"$mnTknOfst 1);
  1287.         $lineno++;
  1288.         $n $this->nstate;
  1289.         while ($n && $this->sorted[$n 1]->iTknOfst == PHP_ParserGenerator_Data::NO_OFFSET{
  1290.             $n--;
  1291.         }
  1292.         fprintf($out"    const YY_SHIFT_MAX = %d;\n"$n 1);
  1293.         $lineno++;
  1294.         fwrite($out"    static public \$yy_shift_ofst = array(\n");
  1295.         $lineno++;
  1296.         for ($i $j 0$i $n$i++{
  1297.             $stp $this->sorted[$i];
  1298.             $ofst $stp->iTknOfst;
  1299.             if ($ofst === PHP_ParserGenerator_Data::NO_OFFSET{
  1300.                 $ofst $mnTknOfst 1;
  1301.             }
  1302.             // change next line
  1303.             if ($j === 0{
  1304.                 fprintf($out" /* %5d */ "$i);
  1305.             }
  1306.             fprintf($out" %4d,"$ofst);
  1307.             if ($j == || $i == $n 1{
  1308.                 fwrite($out"\n");
  1309.                 $lineno++;
  1310.                 $j 0;
  1311.             else {
  1312.                 $j++;
  1313.             }
  1314.         }
  1315.         fwrite($out");\n");
  1316.         $lineno++;
  1317.  
  1318.  
  1319.         /* Output the yy_reduce_ofst[] table */
  1320.  
  1321.         fprintf($out"    const YY_REDUCE_USE_DFLT = %d;\n"$mnNtOfst 1);
  1322.         $lineno++;
  1323.         $n $this->nstate;
  1324.         while ($n && $this->sorted[$n 1]->iNtOfst == PHP_ParserGenerator_Data::NO_OFFSET{
  1325.             $n--;
  1326.         }
  1327.         fprintf($out"    const YY_REDUCE_MAX = %d;\n"$n 1);
  1328.         $lineno++;
  1329.         fwrite($out"    static public \$yy_reduce_ofst = array(\n");
  1330.         $lineno++;
  1331.         for ($i $j 0$i $n$i++{
  1332.             $stp $this->sorted[$i];
  1333.             $ofst $stp->iNtOfst;
  1334.             if ($ofst == PHP_ParserGenerator_Data::NO_OFFSET{
  1335.                 $ofst $mnNtOfst 1;
  1336.             }
  1337.             // change next line
  1338.             if ($j == 0{
  1339.                 fprintf($out" /* %5d */ "$i);
  1340.             }
  1341.             fprintf($out" %4d,"$ofst);
  1342.             if ($j == || $i == $n 1{
  1343.                 fwrite($out"\n");
  1344.                 $lineno++;
  1345.                 $j 0;
  1346.             else {
  1347.                 $j++;
  1348.             }
  1349.         }
  1350.         fwrite($out");\n");
  1351.         $lineno++;
  1352.  
  1353.         /* Output the expected tokens table */
  1354.  
  1355.         fwrite($out"    static public \$yyExpectedTokens = array(\n");
  1356.         $lineno++;
  1357.         for ($i 0$i $this->nstate$i++{
  1358.             $stp $this->sorted[$i];
  1359.             fwrite($out"        /* $i */ array(");
  1360.             for ($ap $stp->ap$ap$ap $ap->next{
  1361.                 if ($ap->sp->index $this->nterminal{
  1362.                     if ($ap->type == PHP_ParserGenerator_Action::SHIFT ||
  1363.                           $ap->type == PHP_ParserGenerator_Action::REDUCE{
  1364.                         fwrite($out$ap->sp->index ', ');
  1365.                     }       
  1366.                 }
  1367.             }
  1368.             fwrite($out"),\n");
  1369.             $lineno++;
  1370.         }
  1371.         fwrite($out");\n");
  1372.         $lineno++;
  1373.  
  1374.         /* Output the default action table */
  1375.  
  1376.         fwrite($out"    static public \$yy_default = array(\n");
  1377.         $lineno++;
  1378.         $n $this->nstate;
  1379.         for ($i $j 0$i $n$i++{
  1380.             $stp $this->sorted[$i];
  1381.             // change next line
  1382.             if ($j == 0{
  1383.                 fprintf($out" /* %5d */ "$i);
  1384.             }
  1385.             fprintf($out" %4d,"$stp->iDflt);
  1386.             if ($j == || $i == $n 1{
  1387.                 fprintf($out"\n")$lineno++;
  1388.                 $j 0;
  1389.             else {
  1390.                 $j++;
  1391.             }
  1392.         }
  1393.         fwrite($out");\n");
  1394.         $lineno++;
  1395.         $this->tplt_xfer($this->name$in$out$lineno);
  1396.  
  1397.         /* Generate the defines */
  1398.         fprintf($out"    const YYNOCODE = %d;\n"$this->nsymbol + 1);
  1399.         $lineno++;
  1400.         if ($this->stacksize{
  1401.             if($this->stacksize <= 0{
  1402.                 PHP_ParserGenerator::ErrorMsg($this->filename0,
  1403.                     "Illegal stack size: [%s].  The stack size should be an integer constant.",
  1404.                     $this->stacksize);
  1405.                 $this->errorcnt++;
  1406.                 $this->stacksize = "100";
  1407.             }
  1408.             fprintf($out"    const YYSTACKDEPTH = %s;\n"$this->stacksize);
  1409.             $lineno++;
  1410.         else {
  1411.             fwrite($out,"    const YYSTACKDEPTH = 100;\n");
  1412.             $lineno++;
  1413.         }
  1414.         fprintf($out"    const YYNSTATE = %d;\n"$this->nstate);
  1415.         $lineno++;
  1416.         fprintf($out"    const YYNRULE = %d;\n"$this->nrule);
  1417.         $lineno++;
  1418.         fprintf($out"    const YYERRORSYMBOL = %d;\n"$this->errsym->index);
  1419.         $lineno++;
  1420.         fprintf($out"    const YYERRSYMDT = 'yy%d';\n"$this->errsym->dtnum);
  1421.         $lineno++;
  1422.         if ($this->has_fallback{
  1423.             fwrite($out"    const YYFALLBACK = 1;\n");
  1424.         else {
  1425.             fwrite($out"    const YYFALLBACK = 0;\n");
  1426.         }
  1427.         $lineno++;
  1428.         $this->tplt_xfer($this->name$in$out$lineno);
  1429.  
  1430.         /* Generate the table of fallback tokens.
  1431.         */
  1432.  
  1433.         if ($this->has_fallback{
  1434.             for ($i 0$i $this->nterminal$i++{
  1435.                 $p $this->symbols[$i];
  1436.                 if ($p->fallback === 0{
  1437.                     // change next line
  1438.                     fprintf($out"    0,  /* %10s => nothing */\n"$p->name);
  1439.                 else {
  1440.                     // change next line
  1441.                     fprintf($out"  %3d,  /* %10s => %s */\n",
  1442.                         $p->fallback->index$p->name$p->fallback->name);
  1443.                 }
  1444.                 $lineno++;
  1445.             }
  1446.         }
  1447.         $this->tplt_xfer($this->name$in$out$lineno);
  1448.  
  1449.  
  1450.         /* Generate a table containing the symbolic name of every symbol
  1451.             ($yyTokenName)
  1452.         */
  1453.  
  1454.         for ($i 0$i $this->nsymbol$i++{
  1455.             fprintf($out,"  %-15s""'" $this->symbols[$i]->name "',");
  1456.             if (($i 3== 3{
  1457.                 fwrite($out,"\n");
  1458.                 $lineno++;
  1459.             }
  1460.         }
  1461.         if (($i 3!= 0{
  1462.             fwrite($out"\n");
  1463.             $lineno++;
  1464.         }
  1465.         $this->tplt_xfer($this->name$in$out$lineno);
  1466.  
  1467.         /* Generate a table containing a text string that describes every
  1468.         ** rule in the rule set of the grammer.  This information is used
  1469.         ** when tracing REDUCE actions.
  1470.         */
  1471.  
  1472.         for ($i 0$rp $this->rule$rp$rp $rp->next$i++{
  1473.             if ($rp->index !== $i{
  1474.                 throw new Exception('rp->index != i and should be');
  1475.             }
  1476.             // change next line
  1477.             fprintf($out" /* %3d */ \"%s ::="$i$rp->lhs->name);
  1478.             for ($j 0$j $rp->nrhs$j++{
  1479.                 $sp $rp->rhs[$j];
  1480.                 fwrite($out,' ' $sp->name);
  1481.                 if ($sp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL{
  1482.                     for($k 1$k $sp->nsubsym$k++{
  1483.                         fwrite($out'|' $sp->subsym[$k]->name);
  1484.                     }
  1485.                 }
  1486.             }
  1487.             fwrite($out"\",\n");
  1488.             $lineno++;
  1489.         }
  1490.         $this->tplt_xfer($this->name$in$out$lineno);
  1491.  
  1492.         /* Generate code which executes every time a symbol is popped from
  1493.         ** the stack while processing errors or while destroying the parser. 
  1494.         ** (In other words, generate the %destructor actions)
  1495.         */
  1496.  
  1497.         if ($this->tokendest{
  1498.             for ($i 0$i $this->nsymbol$i++{
  1499.                 $sp $this->symbols[$i];
  1500.                 if ($sp === || $sp->type != PHP_ParserGenerator_Symbol::TERMINAL{
  1501.                     continue;
  1502.                 }
  1503.                 fprintf($out"    case %d:\n"$sp->index);
  1504.                 $lineno++;
  1505.             }
  1506.             for ($i 0$i $this->nsymbol &&
  1507.                          $this->symbols[$i]->type != PHP_ParserGenerator_Symbol::TERMINAL$i++);
  1508.             if ($i $this->nsymbol{
  1509.                 $this->emit_destructor_code($out$this->symbols[$i]$lineno);
  1510.                 fprintf($out"      break;\n");
  1511.                 $lineno++;
  1512.             }
  1513.         }
  1514.         if ($this->vardest{
  1515.             $dflt_sp 0;
  1516.             for ($i 0$i $this->nsymbol$i++{
  1517.                 $sp $this->symbols[$i];
  1518.                 if ($sp === || $sp->type == PHP_ParserGenerator_Symbol::TERMINAL ||
  1519.                       $sp->index <= || $sp->destructor != 0{
  1520.                     continue;
  1521.                 }
  1522.                 fprintf($out"    case %d:\n"$sp->index);
  1523.                 $lineno++;
  1524.                 $dflt_sp $sp;
  1525.             }
  1526.             if ($dflt_sp != 0{
  1527.                 $this->emit_destructor_code($out$dflt_sp$lineno);
  1528.                 fwrite($out"      break;\n");
  1529.                 $lineno++;
  1530.             }
  1531.         }
  1532.         for ($i 0$i $this->nsymbol$i++{
  1533.             $sp $this->symbols[$i];
  1534.             if ($sp === || $sp->type == PHP_ParserGenerator_Symbol::TERMINAL ||
  1535.                   $sp->destructor === 0{
  1536.                 continue;
  1537.             }
  1538.             fprintf($out"    case %d:\n"$sp->index);
  1539.             $lineno++;
  1540.  
  1541.             /* Combine duplicate destructors into a single case */
  1542.  
  1543.             for ($j $i 1$j $this->nsymbol$j++{
  1544.                 $sp2 $this->symbols[$j];
  1545.                 if ($sp2 && $sp2->type != PHP_ParserGenerator_Symbol::TERMINAL && $sp2->destructor
  1546.                       && $sp2->dtnum == $sp->dtnum
  1547.                       && $sp->destructor == $sp2->destructor{
  1548.                     fprintf($out"    case %d:\n"$sp2->index);
  1549.                     $lineno++;
  1550.                     $sp2->destructor 0;
  1551.                 }
  1552.             }
  1553.         
  1554.             $this->emit_destructor_code($out$this->symbols[$i]$lineno);
  1555.             fprintf($out"      break;\n");
  1556.             $lineno++;
  1557.         }
  1558.         $this->tplt_xfer($this->name$in$out$lineno);
  1559.  
  1560.         /* Generate code which executes whenever the parser stack overflows */
  1561.  
  1562.         $this->tplt_print($out$this->overflow$this->overflowln$lineno);
  1563.         $this->tplt_xfer($this->name$in$out$lineno);
  1564.  
  1565.         /* Generate the table of rule information 
  1566.         **
  1567.         ** Note: This code depends on the fact that rules are number
  1568.         ** sequentually beginning with 0.
  1569.         */
  1570.  
  1571.         for ($rp $this->rule$rp$rp $rp->next{
  1572.             fprintf($out"  array( 'lhs' => %d, 'rhs' => %d ),\n",
  1573.                 $rp->lhs->index$rp->nrhs);
  1574.             $lineno++;
  1575.         }
  1576.         $this->tplt_xfer($this->name$in$out$lineno);
  1577.  
  1578.  
  1579.         /* Generate code which executes during each REDUCE action */
  1580.  
  1581.         for ($rp $this->rule$rp$rp $rp->next{
  1582.             if ($rp->code{
  1583.                 $this->translate_code($rp);
  1584.             }
  1585.         }
  1586.  
  1587.         /* Generate the method map for each REDUCE action */
  1588.  
  1589.         for ($rp $this->rule$rp$rp $rp->next{
  1590.             if ($rp->code === 0{
  1591.                 continue;
  1592.             }
  1593.             fwrite($out'        ' $rp->index ' => ' $rp->index ",\n");
  1594.             $lineno++;
  1595.             for ($rp2 $rp->next$rp2$rp2 $rp2->next{
  1596.                 if ($rp2->code === $rp->code{
  1597.                     fwrite($out'        ' $rp2->index ' => ' .
  1598.                         $rp->index ",\n");
  1599.                     $lineno++;
  1600.                     $rp2->code 0;
  1601.                 }
  1602.             }
  1603.         }
  1604.         $this->tplt_xfer($this->name$in$out$lineno);
  1605.  
  1606.         for ($rp $this->rule$rp$rp $rp->next{
  1607.             if ($rp->code === 0{
  1608.                 continue;
  1609.             }
  1610.             $this->emit_code($out$rp$lineno);
  1611.         }
  1612.         $this->tplt_xfer($this->name$in$out$lineno);
  1613.  
  1614.  
  1615.         /* Generate code which executes if a parse fails */
  1616.  
  1617.         $this->tplt_print($out$this->failure$this->failureln$lineno);
  1618.         $this->tplt_xfer($this->name$in$out$lineno);
  1619.  
  1620.         /* Generate code which executes when a syntax error occurs */
  1621.  
  1622.         $this->tplt_print($out$this->error$this->errorln$lineno);
  1623.         $this->tplt_xfer($this->name$in$out$lineno);
  1624.  
  1625.         /* Generate code which executes when the parser accepts its input */
  1626.  
  1627.         $this->tplt_print($out$this->accept$this->acceptln$lineno);
  1628.         $this->tplt_xfer($this->name$in$out$lineno);
  1629.  
  1630.         /* Append any addition code the user desires */
  1631.  
  1632.         $this->tplt_print($out$this->extracode$this->extracodeln$lineno);
  1633.  
  1634.         fclose($in);
  1635.         fclose($out);
  1636.     }
  1637.  
  1638.     /**
  1639.      * Generate code which executes when the rule "rp" is reduced.  Write
  1640.      * the code to "out".  Make sure lineno stays up-to-date.
  1641.      */
  1642.     function emit_code($outPHP_ParserGenerator_Rule $rp&$lineno)
  1643.     {
  1644.         $linecnt 0;
  1645.         
  1646.         /* Generate code to do the reduce action */
  1647.         if ($rp->code{
  1648.             $this->tplt_linedir($out$rp->line$this->filename);
  1649.             fwrite($out"    function yy_r$rp->index(){$rp->code);
  1650.             $linecnt += count(explode("\n"$rp->code)) 1;
  1651.             $lineno += $linecnt;
  1652.             fwrite($out"    }\n");
  1653.             $this->tplt_linedir($out$lineno$this->outname);
  1654.         /* End if( rp->code ) */
  1655.     }
  1656.  
  1657.     /**
  1658.      * Append text to a dynamically allocated string.  If zText is 0 then
  1659.      * reset the string to be empty again.  Always return the complete text
  1660.      * of the string (which is overwritten with each call).
  1661.      *
  1662.      * n bytes of zText are stored.  If n==0 then all of zText is stored.
  1663.      *
  1664.      * If n==-1, then the previous character is overwritten.
  1665.      * @param string 
  1666.      * @param int 
  1667.      */
  1668.     function append_str($zText$n)
  1669.     {
  1670.         static $z '';
  1671.         $zInt '';
  1672.         
  1673.         if ($zText === ''{
  1674.             $ret $z;
  1675.             $z '';
  1676.             return $ret;
  1677.         }
  1678.         if ($n <= 0{
  1679.             if ($n 0{
  1680.                 if (!strlen($z)) {
  1681.                     throw new Exception('z is zero-length');
  1682.                 }
  1683.                 $z substr($z0strlen($z1);
  1684.                 if (!$z{
  1685.                     $z '';
  1686.                 }
  1687.             }
  1688.             $n strlen($zText);
  1689.         }
  1690.         $i 0;
  1691.         $z .= substr($zText0$n);
  1692.         return $z;
  1693.     }
  1694.  
  1695.     /**
  1696.      * zCode is a string that is the action associated with a rule.  Expand
  1697.      * the symbols in this string so that the refer to elements of the parser
  1698.      * stack.
  1699.      */
  1700.     function translate_code(PHP_ParserGenerator_Rule $rp)
  1701.     {
  1702.         $lhsused 0;    /* True if the LHS element has been used */
  1703.         $used array();   /* True for each RHS element which is used */
  1704.     
  1705.         for($i 0$i $rp->nrhs$i++{
  1706.             $used[$i0;
  1707.         }
  1708.         
  1709.         $this->append_str(''0);
  1710.         for ($i 0$i strlen($rp->code)$i++{
  1711.             $cp $rp->code[$i];
  1712.             if (preg_match('/[A-Za-z]/'$cp&&
  1713.                  ($i === || (!preg_match('/[A-Za-z0-9_]/'$rp->code[$i 1])))) {
  1714.                 //*xp = 0;
  1715.                 // previous line is in essence a temporary substr, so
  1716.                 // we will simulate it
  1717.                 $test substr($rp->code$i);
  1718.                 preg_match('/[A-Za-z0-9_]+/'$test$matches);
  1719.                 $tempcp $matches[0];
  1720.                 $j strlen($tempcp$i;
  1721.                 if ($rp->lhsalias && $tempcp == $rp->lhsalias{
  1722.                     $this->append_str("\$this->_retvalue"0);
  1723.                     $cp $rp->code[$j];
  1724.                     $i $j;
  1725.                     $lhsused 1;
  1726.                 else {
  1727.                     for ($ii 0$ii $rp->nrhs$ii++{
  1728.                         if ($rp->rhsalias[$ii&& $tempcp == $rp->rhsalias[$ii]{
  1729.                             if ($ii !== && $rp->code[$ii 1== '@'{
  1730.                                 /* If the argument is of the form @X then substitute
  1731.                                 ** the token number of X, not the value of X */
  1732.                                 $this->append_str("\$this->yystack[\$this->yyidx + " .
  1733.                                     ($ii $rp->nrhs 1"]->major"-1);
  1734.                             else {
  1735.                                 $sp $rp->rhs[$ii];
  1736.                                 if ($sp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL{
  1737.                                     $dtnum $sp->subsym[0]->dtnum;
  1738.                                 else {
  1739.                                     $dtnum $sp->dtnum;
  1740.                                 }
  1741.                                 $this->append_str("\$this->yystack[\$this->yyidx + " .
  1742.                                     ($ii $rp->nrhs 1"]->minor"0);
  1743.                             }
  1744.                             $cp $rp->code[$j];
  1745.                             $i $j;
  1746.                             $used[$ii1;
  1747.                             break;
  1748.                         }
  1749.                     }
  1750.                 }
  1751.             }
  1752.             $this->append_str($cp1);
  1753.         /* End loop */
  1754.         
  1755.         /* Check to make sure the LHS has been used */
  1756.         if ($rp->lhsalias && !$lhsused{
  1757.             PHP_ParserGenerator::ErrorMsg($this->filename$rp->ruleline,
  1758.                 "Label \"%s\" for \"%s(%s)\" is never used.",
  1759.                 $rp->lhsalias$rp->lhs->name$rp->lhsalias);
  1760.                 $this->errorcnt++;
  1761.         }
  1762.         
  1763.         /* Generate destructor code for RHS symbols which are not used in the
  1764.         ** reduce code */
  1765.         for($i 0$i $rp->nrhs$i++{
  1766.             if ($rp->rhsalias[$i&& !isset($used[$i])) {
  1767.                 PHP_ParserGenerator::ErrorMsg($this->filename$rp->ruleline,
  1768.                     "Label %s for \"%s(%s)\" is never used.",
  1769.                     $rp->rhsalias[$i]$rp->rhs[$i]->name$rp->rhsalias[$i]);
  1770.                 $this->errorcnt++;
  1771.             elseif ($rp->rhsalias[$i== 0{
  1772.                 if ($rp->rhs[$i]->type == PHP_ParserGenerator_Symbol::TERMINAL{
  1773.                     $hasdestructor $this->tokendest != 0;
  1774.                 }else{
  1775.                     $hasdestructor $this->vardest !== || $rp->rhs[$i]->destructor !== 0;
  1776.                 }
  1777.                 if ($hasdestructor{
  1778.                     $this->append_str("  \$this->yy_destructor(" .
  1779.                         ($rp->rhs[$i]->index", \$this->yystack[\$this->yyidx + " .
  1780.                         ($i $rp->nrhs 1"]->minor);\n"0);
  1781.                 else {
  1782.                     /* No destructor defined for this term */
  1783.                 }
  1784.             }
  1785.         }
  1786.         $cp $this->append_str(''0);
  1787.         $rp->code $cp;
  1788.     }
  1789.  
  1790.     /**
  1791.      * The following routine emits code for the destructor for the
  1792.      * symbol sp
  1793.      */
  1794.     function emit_destructor_code($outPHP_ParserGenerator_Symbol $sp&$lineno)
  1795. //    FILE *out;
  1796. //    struct symbol *sp;
  1797. //    struct lemon *lemp;
  1798. //    int *lineno;
  1799.     
  1800.     {
  1801.         $cp 0;
  1802.         
  1803.         $linecnt 0;
  1804.         if ($sp->type == PHP_ParserGenerator_Symbol::TERMINAL{
  1805.             $cp $this->tokendest;
  1806.             if ($cp === 0{
  1807.                 return;
  1808.             }
  1809.             $this->tplt_linedir($out$this->tokendestln$this->filename);
  1810.             fwrite($out"{");
  1811.         elseif ($sp->destructor{
  1812.             $cp $sp->destructor;
  1813.             $this->tplt_linedir($out$sp->destructorln$this->filename);
  1814.             fwrite($out"{");
  1815.         elseif ($this->vardest{
  1816.             $cp $this->vardest;
  1817.             if ($cp === 0{
  1818.                 return;
  1819.             }
  1820.             $this->tplt_linedir($out$this->vardestln$this->filename);
  1821.             fwrite($out"{");
  1822.         else {
  1823.             throw new Exception('emit_destructor')/* Cannot happen */
  1824.         }
  1825.         for ($i 0$i strlen($cp)$i++{
  1826.             if ($cp[$i]=='$' && $cp[$i 1]=='$' {
  1827.                 fprintf($out"(yypminor->yy%d)"$sp->dtnum);
  1828.                 $i++;
  1829.                 continue;
  1830.             }
  1831.             if ($cp[$i== "\n"{
  1832.                 $linecnt++;
  1833.             }
  1834.             fwrite($out$cp[$i]);
  1835.         }
  1836.         $lineno += $linecnt;
  1837.         fwrite($out"}\n");
  1838.         $this->tplt_linedir($out$lineno$this->outname);
  1839.     }
  1840.  
  1841.     /**
  1842.      * Compare to axset structures for sorting purposes
  1843.      */
  1844.     static function axset_compare($a$b)
  1845.     {
  1846.         return $b['nAction'$a['nAction'];
  1847.     }
  1848. }

Documentation generated on Sun, 02 Jul 2006 09:11:00 -0400 by phpDocumentor 1.3.0