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

Source for file Main.php

Documentation is available at Main.php

  1. <?php
  2. define('NO_OFFSET'-2147483647);
  3. define('DEBUG'0);
  4.  
  5. class LemonStateNode
  6. {
  7.     public $key;
  8.     public $data;
  9.     public $from = 0;
  10.     public $next = 0;
  11. }
  12.  
  13.  
  14. /**
  15.  * The state of the yy_action table under construction is an instance of
  16.  * the following structure
  17.  */
  18. class LemonActtab
  19. {
  20.     public $nAction = 0;                 /* Number of used slots in aAction[] */
  21.     public $aAction =                  /* The yy_action[] table under construction */
  22.         array(array(
  23.             'lookahead' => -1,             /* Value of the lookahead token */
  24.             'action' => -1                /* Action to take on the given lookahead */
  25.         ));
  26.     public $aLookahead =               /* A single new transaction set */
  27.         array(array(
  28.             'lookahead' => 0,             /* Value of the lookahead token */
  29.             'action' => 0                /* Action to take on the given lookahead */
  30.         ));
  31.     public $mnLookahead = 0;             /* Minimum aLookahead[].lookahead */
  32.     public $mnAction = 0;                /* Action associated with mnLookahead */
  33.     public $mxLookahead = 0;             /* Maximum aLookahead[].lookahead */
  34.     public $nLookahead = 0;              /* Used slots in aLookahead[] */
  35.  
  36.     /**
  37.      * Add a new action to the current transaction set
  38.      * @param int 
  39.      * @param int 
  40.      */
  41.     function acttab_action($lookahead$action)
  42.     {
  43.         if ($this->nLookahead === 0{
  44.             $this->aLookahead = array();
  45.             $this->mxLookahead $lookahead;
  46.             $this->mnLookahead $lookahead;
  47.             $this->mnAction $action;
  48.         else {
  49.             if ($this->mxLookahead $lookahead{
  50.                 $this->mxLookahead $lookahead;
  51.             }
  52.             if ($this->mnLookahead $lookahead{
  53.                 $this->mnLookahead $lookahead;
  54.                 $this->mnAction $action;
  55.             }
  56.         }
  57.         $this->aLookahead[$this->nLookahead= array(
  58.             'lookahead' => $lookahead,
  59.             'action' => $action);
  60.         $this->nLookahead++;
  61.     }
  62.  
  63.     /**
  64.      * Add the transaction set built up with prior calls to acttab_action()
  65.      * into the current action table.  Then reset the transaction set back
  66.      * to an empty set in preparation for a new round of acttab_action() calls.
  67.      *
  68.      * Return the offset into the action table of the new transaction.
  69.      */
  70.     function acttab_insert()
  71.     {
  72.         if ($this->nLookahead <= 0{
  73.             throw new Exception('nLookahead is not set up?');
  74.         }
  75.     
  76.         /* Scan the existing action table looking for an offset where we can
  77.         ** insert the current transaction set.  Fall out of the loop when that
  78.         ** offset is found.  In the worst case, we fall out of the loop when
  79.         ** i reaches $this->nAction, which means we append the new transaction set.
  80.         **
  81.         ** i is the index in $this->aAction[] where $this->mnLookahead is inserted.
  82.         */
  83.         for ($i = 0; $i $this->nAction $this->mnLookahead$i++{
  84.             if (!isset($this->aAction[$i])) {
  85.                 $this->aAction[$i= array(
  86.                     'lookahead' => -1,
  87.                     'action' => -1,
  88.                 );
  89.             }
  90.             if ($this->aAction[$i]['lookahead'< 0{
  91.                 for ($j = 0; $j $this->nLookahead$j++{
  92.                     if (!isset($this->aLookahead[$j])) {
  93.                         $this->aLookahead[$j= array(
  94.                             'lookahead' => 0,
  95.                             'action' => 0,
  96.                         );
  97.                     }
  98.                     $k $this->aLookahead[$j]['lookahead'-
  99.                         $this->mnLookahead $i;
  100.                     if ($k < 0{
  101.                         break;
  102.                     }
  103.                     if (!isset($this->aAction[$k])) {
  104.                         $this->aAction[$k= array(
  105.                             'lookahead' => -1,
  106.                             'action' => -1,
  107.                         );
  108.                     }
  109.                     if ($this->aAction[$k]['lookahead'>= 0{
  110.                         break;
  111.                     }
  112.                 }
  113.                 if ($j $this->nLookahead {
  114.                     continue;
  115.                 }
  116.                 for ($j = 0; $j $this->nAction$j++{
  117.                     if (!isset($this->aAction[$j])) {
  118.                         $this->aAction[$j= array(
  119.                             'lookahead' => -1,
  120.                             'action' => -1,
  121.                         );
  122.                     }
  123.                     if ($this->aAction[$j]['lookahead'== $j +
  124.                           $this->mnLookahead $i{
  125.                         break;
  126.                     }
  127.                 }
  128.                 if ($j == $this->nAction{
  129.                     break;  /* Fits in empty slots */
  130.                 }
  131.             elseif ($this->aAction[$i]['lookahead'== $this->mnLookahead{
  132.                 if ($this->aAction[$i]['action'!= $this->mnAction{
  133.                     continue;
  134.                 }
  135.                 for ($j = 0; $j $this->nLookahead$j++{
  136.                     $k $this->aLookahead[$j]['lookahead'-
  137.                         $this->mnLookahead $i;
  138.                     if ($k < 0 || $k >= $this->nAction{
  139.                         break;
  140.                     }
  141.                     if (!isset($this->aAction[$k])) {
  142.                         $this->aAction[$k= array(
  143.                             'lookahead' => -1,
  144.                             'action' => -1,
  145.                         );
  146.                     }
  147.                     if ($this->aLookahead[$j]['lookahead'!= 
  148.                           $this->aAction[$k]['lookahead']{
  149.                         break;
  150.                     }
  151.                     if ($this->aLookahead[$j]['action'!=
  152.                           $this->aAction[$k]['action']{
  153.                         break;
  154.                     }
  155.                 }
  156.                 if ($j $this->nLookahead{
  157.                     continue;
  158.                 }
  159.                 $n = 0;
  160.                 for ($j = 0; $j $this->nAction$j++{
  161.                     if (!isset($this->aAction[$j])) {
  162.                         $this->aAction[$j= array(
  163.                             'lookahead' => -1,
  164.                             'action' => -1,
  165.                         );
  166.                     }
  167.                     if ($this->aAction[$j]['lookahead'< 0{
  168.                         continue;
  169.                     }
  170.                     if ($this->aAction[$j]['lookahead'== $j +
  171.                           $this->mnLookahead $i{
  172.                         $n++;
  173.                     }
  174.                 }
  175.                 if ($n == $this->nLookahead{
  176.                     break;  /* Same as a prior transaction set */
  177.                 }
  178.             }
  179.         }
  180.         /* Insert transaction set at index i. */
  181.         for ($j = 0; $j $this->nLookahead$j++{
  182.             if (!isset($this->aLookahead[$j])) {
  183.                 $this->aLookahead[$j= array(
  184.                     'lookahead' => 0,
  185.                     'action' => 0,
  186.                 );
  187.             }
  188.             $k $this->aLookahead[$j]['lookahead'$this->mnLookahead $i;
  189.             $this->aAction[$k$this->aLookahead[$j];
  190.             if ($k >= $this->nAction{
  191.                 $this->nAction $k + 1;
  192.             }
  193.         }
  194.         $this->nLookahead = 0;
  195.         $this->aLookahead = array();
  196.  
  197.         /* Return the offset that is added to the lookahead in order to get the
  198.         ** index into yy_action of the action */
  199.         return $i $this->mnLookahead;
  200.     }
  201. }
  202.  
  203. /* Symbols (terminals and nonterminals) of the grammar are stored
  204. ** in the following: */
  205. class LemonSymbol
  206. {
  207.     const TERMINAL = 1;
  208.     const NONTERMINAL = 2;
  209.     const MULTITERMINAL = 3;
  210.     
  211.     const LEFT = 1;
  212.     const RIGHT = 2;
  213.     const NONE = 3;
  214.     const UNK = 4;
  215.     public $name;          /* Name of the symbol */
  216.     public $index;         /* Index number for this symbol */
  217.   /* enum {
  218.     TERMINAL,
  219.     NONTERMINAL,
  220.     MULTITERMINAL
  221.   } */
  222.     public $type;          /* Symbols are all either TERMINALS or NTs */
  223.     /**
  224.      * @var LemonRule 
  225.      */
  226.     public $rule/* Linked list of rules of this (if an NT) */
  227.     /**
  228.      * @var LemonSymbol 
  229.      */
  230.     public $fallback;      /* fallback token in case this token doesn't parse */
  231.     public $prec;          /* Precedence if defined (-1 otherwise) */
  232.   /* enum e_assoc {
  233.     LEFT,
  234.     RIGHT,
  235.     NONE,
  236.     UNK
  237.   } */
  238.     public $assoc;         /* Associativity if predecence is defined */
  239.     public $firstset;      /* First-set for all rules of this symbol */
  240.     /**
  241.      * @var boolean 
  242.      */
  243.     public $lambda;        /* True if NT and can generate an empty string */
  244.     public $destructor = 0;    /* Code which executes whenever this symbol is
  245.                            ** popped from the stack during error processing */
  246.     public $destructorln;  /* Line number of destructor code */
  247.     public $datatype;      /* The data type of information held by this
  248.                            ** object. Only used if type==NONTERMINAL */
  249.     public $dtnum;         /* The data type number.  In the parser, the value
  250.                            ** stack is a union.  The .yy%d element of this
  251.                            ** union is the correct data type for this object */
  252.     /* The following fields are used by MULTITERMINALs only */
  253.     public $nsubsym;           /* Number of constituent symbols in the MULTI */
  254.     /**
  255.      * @var array an array of {@link LemonSymbol} objects
  256.      */
  257.     public $subsym = array();  /* Array of constituent symbols */
  258.     private static $symbol_table = array();
  259.     /**
  260.      * Return a pointer to the (terminal or nonterminal) symbol "x".
  261.      * Create a new symbol if this is the first time "x" has been seen.
  262.      * (this is a singleton)
  263.      * @param string 
  264.      * @return LemonSymbol 
  265.      */
  266.     public static function Symbol_new($x)
  267.     {
  268.         if (isset(self::$symbol_table[$x])) {
  269.             return self::$symbol_table[$x];
  270.         }
  271.         $sp = new LemonSymbol;
  272.         $sp->name = $x;
  273.         $sp->type = preg_match('/[A-Z]/'$x[0]? self::TERMINAL : self::NONTERMINAL;
  274.         $sp->rule = 0;
  275.         $sp->fallback = 0;
  276.         $sp->prec = -1;
  277.         $sp->assoc = self::UNK;
  278.         $sp->firstset = array();
  279.         $sp->lambda = false;
  280.         $sp->destructor = 0;
  281.         $sp->datatype = 0;
  282.         self::$symbol_table[$sp->name$sp;
  283.         return $sp;
  284.     }
  285.  
  286.     /**
  287.      * Return the number of unique symbols
  288.      * @return int 
  289.      */
  290.     public static function Symbol_count()
  291.     {
  292.         return count(self::$symbol_table);
  293.     }
  294.  
  295.     public static function Symbol_arrayof()
  296.     {
  297.         return array_values(self::$symbol_table);
  298.     }
  299.  
  300.     public static function Symbol_find($x)
  301.     {
  302.         if (isset(self::$symbol_table[$x])) {
  303.             return self::$symbol_table[$x];
  304.         }
  305.         return 0;
  306.     }
  307.  
  308.     /**
  309.      * Sort function helper for symbols
  310.      * 
  311.      * Symbols that begin with upper case letters (terminals or tokens)
  312.      * must sort before symbols that begin with lower case letters
  313.      * (non-terminals).  Other than that, the order does not matter.
  314.      * 
  315.      * We find experimentally that leaving the symbols in their original
  316.      * order (the order they appeared in the grammar file) gives the
  317.      * smallest parser tables in SQLite.
  318.      * @param LemonSymbol 
  319.      * @param LemonSymbol 
  320.      */
  321.     public static function sortSymbols($a$b)
  322.     {
  323.         $i1 $a->index + 10000000*(ord($a->name[0]ord('Z'));
  324.         $i2 $b->index + 10000000*(ord($b->name[0]ord('Z'));
  325.         return $i1 $i2;
  326.     }
  327.  
  328.     /**
  329.      * Return true if two symbols are the same.
  330.      */
  331.     public static function same_symbol(LemonSymbol $aLemonSymbol $b)
  332.     {
  333.         if ($a === $breturn 1;
  334.         if ($a->type != self::MULTITERMINALreturn 0;
  335.         if ($b->type != self::MULTITERMINALreturn 0;
  336.         if ($a->nsubsym != $b->nsubsymreturn 0;
  337.         for ($i = 0; $i $a->nsubsym; $i++{
  338.             if ($a->subsym[$i!= $b->subsym[$i]return 0;
  339.         }
  340.         return 1;
  341.     }
  342. }
  343.  
  344. /* Each production rule in the grammar is stored in the following
  345. ** structure.  */
  346. class LemonRule {
  347.     /**
  348.      * @var array an array of {@link LemonSymbol} objects
  349.      */
  350.     public $lhs;      /* Left-hand side of the rule */
  351.     public $lhsalias = array();          /* Alias for the LHS (NULL if none) */
  352.     public $ruleline;            /* Line number for the rule */
  353.     public $nrhs;                /* Number of RHS symbols */
  354.     /**
  355.      * @var array an array of {@link LemonSymbol} objects
  356.      */
  357.     public $rhs;     /* The RHS symbols */
  358.     public $rhsalias = array();         /* An alias for each RHS symbol (NULL if none) */
  359.     public $line;                /* Line number at which code begins */
  360.     public $code;              /* The code executed when this rule is reduced */
  361.     /**
  362.      * @var LemonSymbol 
  363.      */
  364.     public $precsym;  /* Precedence symbol for this rule */
  365.     public $index;               /* An index number for this rule */
  366.     public $canReduce;       /* True if this rule is ever reduced */
  367.     /**
  368.      * @var LemonRule 
  369.      */
  370.     public $nextlhs;    /* Next rule with the same LHS */
  371.     /**
  372.      * @var LemonRule 
  373.      */
  374.     public $next;       /* Next rule in the global list */
  375. }
  376.  
  377. /* A configuration is a production rule of the grammar together with
  378. ** a mark (dot) showing how much of that rule has been processed so far.
  379. ** Configurations also contain a follow-set which is a list of terminal
  380. ** symbols which are allowed to immediately follow the end of the rule.
  381. ** Every configuration is recorded as an instance of the following: */
  382. class LemonConfig {
  383.     const COMPLETE = 1;
  384.     const INCOMPLETE = 2;
  385.     /**
  386.      * @var LemonRule 
  387.      */
  388.     public $rp;         /* The rule upon which the configuration is based */
  389.     public $dot;                 /* The parse point */
  390.     public $fws;               /* Follow-set for this configuration only */
  391.     /**
  392.      * @var LemonPlink 
  393.      */
  394.     public $fplp;      /* Follow-set forward propagation links */
  395.     /**
  396.      * @var LemonPlink 
  397.      */
  398.     public $bplp;      /* Follow-set backwards propagation links */
  399.     /**
  400.      * @var LemonState 
  401.      */
  402.     public $stp;       /* Pointer to state which contains this */
  403.   /* enum {
  404.     COMPLETE,              /* The status is used during followset and
  405.     INCOMPLETE             /*    shift computations
  406.   } */
  407.     public $status;
  408.     /**
  409.      * Index of next LemonConfig object
  410.      * @var int 
  411.      */
  412.     public $next;     /* Next configuration in the state */
  413.     /**
  414.      * Index of the next basis configuration LemonConfig object
  415.      * @var int 
  416.      */
  417.     public $bp;       /* The next basis configuration */
  418.  
  419.     /**
  420.      * @var LemonConfig 
  421.      */
  422.     static public $current;      /* Top of list of configs */
  423.     /**
  424.      * @var LemonConfig 
  425.      */
  426.     static public $currentend;      /* Last on list of configs */
  427.  
  428.     /**
  429.      * @var LemonConfig 
  430.      */
  431.     static public $basis;      /* Top of list of basis configs */
  432.     /**
  433.      * @var LemonConfig 
  434.      */
  435.     static public $basisend;      /* Last on list of basis configs */
  436.     
  437.     static public $x4a = array();
  438.  
  439.     /**
  440.      * Return a pointer to a new configuration
  441.      * @return LemonConfig 
  442.      */
  443.     private static function newconfig()
  444.     {
  445.         return new LemonConfig;
  446.     }
  447.  
  448.     static function Configshow(LemonConfig $cfp)
  449.     {
  450.         $fp fopen('php://output''w');
  451.         while ($cfp{
  452.             if ($cfp->dot == $cfp->rp->nrhs{
  453.                 $buf sprintf('(%d)'$cfp->rp->index);
  454.                 fprintf($fp'    %5s '$buf);
  455.             else {
  456.                 fwrite($fp,'          ');
  457.             }
  458.             $cfp->ConfigPrint($fp);
  459.             fwrite($fp"\n");
  460.             if (0{
  461.                 //SetPrint(fp,cfp->fws,$this);
  462.                 //PlinkPrint(fp,cfp->fplp,"To  ");
  463.                 //PlinkPrint(fp,cfp->bplp,"From");
  464.             }
  465.             $cfp $cfp->next;
  466.         }
  467.         fwrite($fp"\n");
  468.         fclose($fp);
  469.     }
  470.  
  471.     /**
  472.      * Initialized the configuration list builder
  473.      */
  474.     static function Configlist_init()
  475.     {
  476.         self::$current = 0;
  477.         self::$currentend &self::$current;
  478.         self::$basis = 0;
  479.         self::$basisend &self::$basis;
  480.         self::$x4a = array();
  481.     }
  482.  
  483.     /**
  484.      * Remove all data from the table.  Pass each data to the function "f"
  485.      * as it is removed.  ("f" may be null to avoid this step.)
  486.      */
  487.     static function Configtable_reset($f)
  488.     {
  489.         self::$current = 0;
  490.         self::$currentend &self::$current;
  491.         self::$basis = 0;
  492.         self::$basisend &self::$basis;
  493.         self::Configtable_clear(0);
  494.     }
  495.  
  496.     /**
  497.      * Remove all data from the table.  Pass each data to the function "f"
  498.      * as it is removed.  ("f" may be null to avoid this step.)
  499.      */
  500.     static function Configtable_clear($f)
  501.     {
  502.         if (!count(self::$x4a)) {
  503.             return;
  504.         }
  505.         if ($f{
  506.             for ($i = 0; $i < count(self::$x4a)$i++{
  507.                 call_user_func($fself::$x4a[$i]->data);
  508.             }
  509.         }
  510.         self::$x4a = array();
  511.     }
  512.  
  513.     /**
  514.      * Initialized the configuration list builder
  515.      */
  516.     static function Configlist_reset()
  517.     {
  518.         self::Configtable_clear(0);
  519.     }
  520.  
  521.     /**
  522.      * Add another configuration to the configuration list
  523.      * @param LemonRule the rule
  524.      * @param int Index into the RHS of the rule where the dot goes
  525.      * @return LemonConfig 
  526.      */
  527.     static function Configlist_add($rp$dot)
  528.     {
  529.         $model = new LemonConfig;
  530.         $model->rp = $rp;
  531.         $model->dot = $dot;
  532.         $cfp = self::Configtable_find($model);
  533.         if ($cfp === 0{
  534.             $cfp = self::newconfig();
  535.             $cfp->rp = $rp;
  536.             $cfp->dot = $dot;
  537.             $cfp->fws = array();
  538.             $cfp->stp = 0;
  539.             $cfp->fplp = $cfp->bplp = 0;
  540.             $cfp->next = 0;
  541.             $cfp->bp = 0;
  542.             self::$currentend $cfp;
  543.             self::$currentend &$cfp->next;
  544.             self::Configtable_insert($cfp);
  545.         }
  546.         return $cfp;
  547.     }
  548.  
  549.     /**
  550.      * Add a basis configuration to the configuration list
  551.      * @param LemonRule 
  552.      * @param int 
  553.      * @return LemonConfig 
  554.      */
  555.     static function Configlist_addbasis($rp$dot)
  556.     {
  557.         $model = new LemonConfig;
  558.         $model->rp = $rp;
  559.         $model->dot = $dot;
  560.         $cfp = self::Configtable_find($model);
  561.         if ($cfp === 0{
  562.             $cfp = self::newconfig();
  563.             $cfp->rp = $rp;
  564.             $cfp->dot = $dot;
  565.             $cfp->fws = array();
  566.             $cfp->stp = 0;
  567.             $cfp->fplp = $cfp->bplp = 0;
  568.             $cfp->next = 0;
  569.             $cfp->bp = 0;
  570.             self::$currentend $cfp;
  571.             self::$currentend &$cfp->next;
  572.             self::$basisend $cfp;
  573.             self::$basisend &$cfp->bp;
  574.             self::Configtable_insert($cfp);
  575.         }
  576.         return $cfp;
  577.     }
  578.  
  579.     /* Compute the closure of the configuration list */
  580.     static function Configlist_closure(LemonData $lemp)
  581.     {
  582.         for ($cfp = self::$current$cfp$cfp $cfp->next{
  583.             $rp $cfp->rp;
  584.             $dot $cfp->dot;
  585.             if ($dot >= $rp->nrhs{
  586.                 continue;
  587.             }
  588.             $sp $rp->rhs[$dot];
  589.             if ($sp->type == LemonSymbol::NONTERMINAL{
  590.                 if ($sp->rule === 0 && $sp !== $lemp->errsym{
  591.                     Lemon::ErrorMsg($lemp->filename$rp->line,
  592.                         "Nonterminal \"%s\" has no rules."$sp->name);
  593.                     $lemp->errorcnt++;
  594.                 }
  595.                 for ($newrp $sp->rule; $newrp$newrp $newrp->nextlhs{
  596.                     $newcfp = self::Configlist_add($newrp0);
  597.                     for ($i $dot + 1; $i $rp->nrhs; $i++{
  598.                         $xsp $rp->rhs[$i];
  599.                         if ($xsp->type == LemonSymbol::TERMINAL{
  600.                             $newcfp->fws[$xsp->index= 1;
  601.                             break;
  602.                         elseif ($xsp->type == LemonSymbol::MULTITERMINAL{
  603.                             for ($k = 0; $k $xsp->nsubsym; $k++{
  604.                                 $newcfp->fws[$xsp->subsym[k]->index= 1;
  605.                             }
  606.                             break;
  607.                         else {
  608.                             $a array_diff_key($xsp->firstset$newcfp->fws);
  609.                             $newcfp->fws += $a;
  610.                             if ($xsp->lambda === false{
  611.                                 break;
  612.                             }
  613.                         }
  614.                     }
  615.                     if ($i == $rp->nrhs{
  616.                         LemonPlink::Plink_add($cfp->fplp$newcfp);
  617.                     }
  618.                 }
  619.             }
  620.         }
  621.     }
  622.  
  623.     /**
  624.      * Sort the configuration list
  625.      */
  626.     static function Configlist_sort()
  627.     {
  628.         $a = 0;
  629.         //self::Configshow(self::$current);
  630.         self::$current = Lemon::msort(self::$current,'next'array('LemonConfig''Configcmp'));
  631.         //self::Configshow(self::$current);
  632.         self::$currentend &$a;
  633.         self::$currentend = 0;
  634.     }
  635.  
  636.     /**
  637.      * Sort the configuration list
  638.      */
  639.     static function Configlist_sortbasis()
  640.     {
  641.         $a = 0;
  642.         self::$basis = Lemon::msort(self::$current,'bp'array('LemonConfig''Configcmp'));
  643.         self::$basisend &$a;
  644.         self::$basisend = 0;
  645.     }
  646.  
  647.     /** Return a pointer to the head of the configuration list and
  648.      * reset the list
  649.      * @return LemonConfig 
  650.      */
  651.     static function Configlist_return()
  652.     {
  653.         $old = self::$current;
  654.         self::$current = 0;
  655.         self::$currentend &self::$current;
  656.         return $old;
  657.     }
  658.  
  659.     /** Return a pointer to the head of the basis list and
  660.      * reset the list
  661.      * @return LemonConfig 
  662.      */
  663.     static function Configlist_basis()
  664.     {
  665.         $old = self::$basis;
  666.         self::$basis = 0;
  667.         self::$basisend &self::$basis;
  668.         return $old;
  669.     }
  670.  
  671.     /**
  672.      * Free all elements of the given configuration list
  673.      * @param LemonConfig 
  674.      */
  675.     static function Configlist_eat($cfp)
  676.     {
  677.         for($cfp$cfp $nextcfp){
  678.             $nextcfp $cfp->next;
  679.             if ($cfp->fplp !=0{
  680.                 throw new Exception('fplp of configuration non-zero?');
  681.             }
  682.             if ($cfp->bplp !=0{
  683.                 throw new Exception('bplp of configuration non-zero?');
  684.             }
  685.             if ($cfp->fws{
  686.                 $cfp->fws = array();
  687.             }
  688.         }
  689.     }
  690.  
  691.     static function Configcmp($a$b)
  692.     {
  693.         $x $a->rp->index - $b->rp->index;
  694.         if (!$x{
  695.             $x $a->dot - $b->dot;
  696.         }
  697.         return $x;
  698.     }
  699.  
  700.     function ConfigPrint($fp)
  701.     {
  702.         $rp $this->rp;
  703.         fprintf($fp"%s ::="$rp->lhs->name);
  704.         for ($i = 0; $i <= $rp->nrhs; $i++{
  705.             if ($i === $this->dot{
  706.                 fwrite($fp,' *');
  707.             }
  708.             if ($i === $rp->nrhs{
  709.                 break;
  710.             }
  711.             $sp $rp->rhs[$i];
  712.             fprintf($fp,' %s'$sp->name);
  713.             if ($sp->type == LemonSymbol::MULTITERMINAL{
  714.                 for ($j = 1; $j $sp->nsubsym; $j++{
  715.                     fprintf($fp'|%s'$sp->subsym[$j]->name);
  716.                 }
  717.             }
  718.         }
  719.     }
  720.  
  721.     /**
  722.      * Hash a configuration
  723.      */
  724.     private static function confighash(LemonConfig $a)
  725.     {
  726.         $h = 0;
  727.         $h $h * 571 + $a->rp->index * 37 + $a->dot;
  728.         return $h;
  729.     }
  730.  
  731.     /**
  732.      * Insert a new record into the array.  Return TRUE if successful.
  733.      * Prior data with the same key is NOT overwritten
  734.      */
  735.     static function Configtable_insert(LemonConfig $data)
  736.     {
  737. //typedef struct s_x4node {
  738. //  struct config *data;                  /* The data */
  739. //  struct s_x4node *next;   /* Next entry with the same hash */
  740. //  struct s_x4node **from;  /* Previous link */
  741. //} x4node;
  742. //
  743. //        x4node *np;
  744. //        int h;
  745. //        int ph;
  746.         
  747.         $h = self::confighash($data);
  748.         if (isset(self::$x4a[$h])) {
  749.             $np = self::$x4a[$h];
  750.         else {
  751.             $np = 0;
  752.         }
  753.         while ($np{
  754.             if (self::Configcmp($np->data$data== 0{
  755.                 /* An existing entry with the same key is found. */
  756.                 /* Fail because overwrite is not allows. */
  757.                 return 0;
  758.             }
  759.             $np $np->next;
  760.         }
  761.         /* Insert the new data */
  762.         $np = array('data' => $data'next' => 0'from' => 0);
  763.         $np = new LemonStateNode;
  764.         $np->data = $data;
  765.         // as you might notice, "from" always points to itself.
  766.         // this bug is in the original lemon parser, but from is never actually accessed
  767.         // so it don't much matter now, do it?
  768.         if (isset(self::$x4a[$h])) {
  769.             self::$x4a[$h]->from = $np->next;
  770.             $np->next = self::$x4a[$h];
  771.         }
  772.         $np->from = $np;
  773.         self::$x4a[$h$np;
  774.         return 1;
  775.     }
  776.  
  777.     /**
  778.      * Return a pointer to data assigned to the given key.  Return NULL
  779.      * if no such key.
  780.      * @return LemonConfig|0
  781.      */
  782.     static function Configtable_find(LemonConfig $key)
  783.     {
  784.         $h = self::confighash($key);
  785.         if (!isset(self::$x4a[$h])) {
  786.             return 0;
  787.         }
  788.         $np = self::$x4a[$h];
  789.         while ($np{
  790.             if (self::Configcmp($np->data$key== 0{
  791.                 break;
  792.             }
  793.             $np $np->next;
  794.         }
  795.         return $np $np->data : 0;
  796.     }
  797. }
  798.  
  799. /* Every shift or reduce operation is stored as one of the following */
  800. class LemonAction {
  801.     const SHIFT = 1ACCEPT = 2REDUCE = 3ERROR = 4CONFLICT = 5SH_RESOLVED = 6,
  802.           RD_RESOLVED = 7NOT_USED = 8;
  803.     /**
  804.      * @var LemonSymbol 
  805.      */
  806.     public $sp;       /* The look-ahead symbol */
  807.   /* enum e_action {
  808.     SHIFT,
  809.     ACCEPT,
  810.     REDUCE,
  811.     ERROR,
  812.     CONFLICT,                /* Was a reduce, but part of a conflict 
  813.     SH_RESOLVED,             /* Was a shift.  Precedence resolved conflict 
  814.     RD_RESOLVED,             /* Was reduce.  Precedence resolved conflict 
  815.     NOT_USED                 /* Deleted by compression 
  816.   } */
  817.     public $type;
  818.   /* union {
  819.     struct state *stp;     /* The new state, if a shift 
  820.     struct rule *rp;       /* The rule, if a reduce 
  821.   } */
  822.     public $x = array('stp' => null'rp' => null);
  823.     /**
  824.      * @var LemonAction 
  825.      */
  826.     public $next;     /* Next action for this state */
  827.     /**
  828.      * @var LemonAction 
  829.      */
  830.     public $collide;  /* Next action with the same hash */
  831.  
  832.     /* Compare two actions */
  833.     static function actioncmp(LemonAction $ap1LemonAction $ap2)
  834.     {
  835.         $rc $ap1->sp->index - $ap2->sp->index;
  836.         if ($rc === 0{
  837.             $rc $ap1->type - $ap2->type;
  838.         }
  839.         if ($rc === 0{
  840.             if ($ap1->type != LemonAction::REDUCE &&
  841.                   $ap1->type != LemonAction::RD_RESOLVED &&
  842.                   $ap1->type != LemonAction::CONFLICT{
  843.                 throw new Exception('action has not been processed: ' .
  844.                     $ap1->sp->name);
  845.             }
  846.             if ($ap2->type != LemonAction::REDUCE &&
  847.                   $ap2->type != LemonAction::RD_RESOLVED &&
  848.                   $ap2->type != LemonAction::CONFLICT{
  849.                 throw new Exception('action has not been processed: ' .
  850.                     $ap2->sp->name);
  851.             }
  852.             $rc $ap1->x->index - $ap2->x->index;
  853.         }
  854.         return $rc;
  855.     }
  856.  
  857.     /**
  858.      * create linked list of LemonActions
  859.      *
  860.      * @param LemonAction|null
  861.      * @param int one of the constants from LemonAction
  862.      * @param LemonSymbol 
  863.      * @param LemonSymbol|LemonRule
  864.      */
  865.     static function Action_add(&$app$typeLemonSymbol $sp$arg)
  866.     {
  867.         $new = new LemonAction;
  868.         $new->next = $app;
  869.         $app $new;
  870.         $new->type = $type;
  871.         $new->sp = $sp;
  872.         $new->x = $arg;
  873.     }
  874.  
  875.     /* Sort parser actions */
  876.     static function Action_sort(LemonAction $ap)
  877.     {
  878.         $ap = Lemon::msort($ap'next'array('LemonAction''actioncmp'));
  879.         return $ap;
  880.     }
  881.  
  882.     /**
  883.      * Print an action to the given file descriptor.  Return FALSE if
  884.      * nothing was actually printed.
  885.      */
  886.     function PrintAction($fp$indent)
  887.     {
  888.         $result = 1;
  889.         switch ($this->type)
  890.         {
  891.             case self::SHIFT:
  892.                 fprintf($fp"%${indent}s shift  %d"$this->sp->name$this->x->statenum);
  893.                 break;
  894.             case self::REDUCE:
  895.                 fprintf($fp"%${indent}s reduce %d"$this->sp->name$this->x->index);
  896.                 break;
  897.             case self::ACCEPT:
  898.                 fprintf($fp"%${indent}s accept"$this->sp->name);
  899.                 break;
  900.             case self::ERROR:
  901.                 fprintf($fp"%${indent}s error"$this->sp->name);
  902.                 break;
  903.             case self::CONFLICT:
  904.                 fprintf($fp"%${indent}s reduce %-3d ** Parsing conflict **"$this->sp->name$this->x->index);
  905.                 break;
  906.             case self::SH_RESOLVED:
  907.             case self::RD_RESOLVED:
  908.             case self::NOT_USED:
  909.                 $result = 0;
  910.                 break;
  911.         }
  912.         return $result;
  913.     }
  914. }
  915.  
  916. /* A followset propagation link indicates that the contents of one
  917. ** configuration followset should be propagated to another whenever
  918. ** the first changes. */
  919. class LemonPlink {
  920.     /**
  921.      * @var LemonConfig 
  922.      */
  923.     public $cfp;      /* The configuration to which linked */
  924.     /**
  925.      * @var LemonPlink 
  926.      */
  927.     public $next = 0;      /* The next propagate link */
  928.  
  929.     /**
  930.      * Add a plink to a plink list
  931.      * @param LemonPlink|null
  932.      * @param LemonConfig 
  933.      */
  934.     static function Plink_add(&$plppLemonConfig $cfp)
  935.     {
  936.         $new = new LemonPlink;
  937.         $new->next = $plpp;
  938.         $plpp $new;
  939.         $new->cfp = $cfp;
  940.     }
  941.  
  942.     /* Transfer every plink on the list "from" to the list "to" */
  943.     static function Plink_copy(LemonPlink &$toLemonPlink $from)
  944.     {
  945.         while ($from{
  946.             $nextpl $from->next;
  947.             $from->next = $to;
  948.             $to $from;
  949.             $from $nextpl;
  950.         }
  951.     }
  952.  
  953.     /**
  954.      * Delete every plink on the list
  955.      * @param LemonPlink|0
  956.      */
  957.     static function Plink_delete($plp)
  958.     {
  959.         while ($plp{
  960.             $nextpl $plp->next;
  961.             $plp->next = 0;
  962.             $plp $nextpl;
  963.         }
  964.     }
  965. }
  966.  
  967. /* Each state of the generated parser's finite state machine
  968. ** is encoded as an instance of the following structure. */
  969. class LemonState {
  970.     /**
  971.      * @var LemonConfig 
  972.      */
  973.     public $bp;       /* The basis configurations for this state */
  974.     /**
  975.      * @var LemonConfig 
  976.      */
  977.     public $cfp;      /* All configurations in this set */
  978.     public $statenum;            /* Sequencial number for this state */
  979.     /**
  980.      * @var LemonAction 
  981.      */
  982.     public $ap;       /* Array of actions for this state */
  983.     public $nTknAct$nNtAct;     /* Number of actions on terminals and nonterminals */
  984.     public $iTknOfst$iNtOfst;   /* yy_action[] offset for terminals and nonterms */
  985.     public $iDflt;               /* Default action */
  986.     public static $x3a = array();
  987.     public static $states = array();
  988.  
  989.     /**
  990.      * Compare two states for sorting purposes.  The smaller state is the
  991.      * one with the most non-terminal actions.  If they have the same number
  992.      * of non-terminal actions, then the smaller is the one with the most
  993.      * token actions.
  994.      */
  995.     static function stateResortCompare($a$b)
  996.     {
  997.         $n $b->nNtAct - $a->nNtAct;
  998.         if ($n === 0{
  999.             $n $b->nTknAct - $a->nTknAct;
  1000.         }
  1001.         return $n;
  1002.     }
  1003.  
  1004.     static function statecmp($a$b)
  1005.     {
  1006.         for ($rc = 0; $rc == 0 && $a && $b;  $a $a->bp$b $b->bp{
  1007.             $rc $a->rp->index - $b->rp->index;
  1008.             if ($rc === 0{
  1009.                 $rc $a->dot - $b->dot;
  1010.             }
  1011.         }
  1012.         if ($rc == 0{
  1013.             if ($a{
  1014.                 $rc = 1;
  1015.             }
  1016.             if ($b{
  1017.                 $rc = -1;
  1018.             }
  1019.         }
  1020.         return $rc;
  1021.     }
  1022.  
  1023.     /* Hash a state */
  1024.     private static function statehash(LemonConfig $a)
  1025.     {
  1026.         $h = 0;
  1027.         while ($a{
  1028.             $h $h * 571 + $a->rp->index * 37 + $a->dot;
  1029.             $a $a->bp;
  1030.         }
  1031.         return (int) $h;
  1032.     }
  1033.  
  1034.     /**
  1035.      * Return a pointer to data assigned to the given key.  Return NULL
  1036.      * if no such key.
  1037.      * @param LemonConfig 
  1038.      * @return null|LemonState
  1039.      */
  1040.     static function State_find(LemonConfig $key)
  1041.     {
  1042.         if (!count(self::$x3a)) {
  1043.             return 0;
  1044.         }
  1045.         $h = self::statehash($key);
  1046.         if (!isset(self::$x3a[$h])) {
  1047.             return 0;
  1048.         }
  1049.         $np = self::$x3a[$h];
  1050.         while ($np{
  1051.             if (self::statecmp($np->key$key== 0{
  1052.                 break;
  1053.             }
  1054.             $np $np->next;
  1055.         }
  1056.         return $np $np->data : 0;
  1057.     }
  1058.  
  1059.     /**
  1060.      * Insert a new record into the array.  Return TRUE if successful.
  1061.      * Prior data with the same key is NOT overwritten
  1062.      *
  1063.      * @param LemonState $state 
  1064.      * @param LemonConfig $key 
  1065.      * @return unknown 
  1066.      */
  1067.     static function State_insert(LemonState $stateLemonConfig $key)
  1068.     {
  1069.         $h = self::statehash($key);
  1070.         if (isset(self::$x3a[$h])) {
  1071.             $np = self::$x3a[$h];
  1072.         else {
  1073.             $np = 0;
  1074.         }
  1075.         while ($np{
  1076.             if (self::statecmp($np->key$key== 0{
  1077.                 /* An existing entry with the same key is found. */
  1078.                 /* Fail because overwrite is not allows. */
  1079.                 return 0;
  1080.             }
  1081.             $np $np->next;
  1082.         }
  1083.         /* Insert the new data */
  1084.         $np = new LemonStateNode;
  1085.         $np->key = $key;
  1086.         $np->data = $state;
  1087.         self::$states[$np;
  1088.         // the original lemon code sets the from link always to itself
  1089.         // setting up a faulty double-linked list
  1090.         // however, the from links are never used, so I suspect a copy/paste
  1091.         // error from a standard algorithm that was never caught
  1092.         if (isset(self::$x3a[$h])) {
  1093.             self::$x3a[$h]->from = $np// lemon has $np->next here
  1094.         else {
  1095.             self::$x3a[$h= 0; // dummy to avoid notice
  1096.         }
  1097.         $np->next = self::$x3a[$h];
  1098.         self::$x3a[$h$np;
  1099.         $np->from = self::$x3a[$h];
  1100.         return 1;
  1101.     }
  1102.  
  1103.     static function State_arrayof()
  1104.     {
  1105.         return self::$states;
  1106.     }
  1107. }
  1108.  
  1109. /* The state vector for the entire parser generator is recorded as
  1110. ** follows.  (LEMON uses no global variables and makes little use of
  1111. ** static variables.  Fields in the following structure can be thought
  1112. ** of as begin global variables in the program.) */
  1113. class LemonData {
  1114.     /**
  1115.      * @var array array of {@link LemonState} objects
  1116.      */
  1117.     public $sorted;   /* Table of states sorted by state number */
  1118.     /**
  1119.      * @var LemonRule 
  1120.      */
  1121.     public $rule;       /* List of all rules */
  1122.     public $nstate;              /* Number of states */
  1123.     public $nrule;               /* Number of rules */
  1124.     public $nsymbol;             /* Number of terminal and nonterminal symbols */
  1125.     public $nterminal;           /* Number of terminal symbols */
  1126.     /**
  1127.      * @var array array of {@link LemonSymbol} objects
  1128.      */
  1129.     public $symbols = array()/* Sorted array of pointers to symbols */
  1130.     public $errorcnt;            /* Number of errors */
  1131.     /**
  1132.      * @var LemonSymbol 
  1133.      */
  1134.     public $errsym;   /* The error symbol */
  1135.     public $name;              /* Name of the generated parser */
  1136.     public $arg;               /* Declaration of the 3th argument to parser */
  1137.     public $tokentype;         /* Type of terminal symbols in the parser stack */
  1138.     public $vartype;           /* The default type of non-terminal symbols */
  1139.     public $start;             /* Name of the start symbol for the grammar */
  1140.     public $stacksize;         /* Size of the parser stack */
  1141.     public $include_code;           /* Code to put at the start of the parser file */
  1142.     public $includeln;          /* Line number for start of include code */
  1143.     public $include_classcode;   /* Code to put in the parser class */
  1144.     public $include_classln;     /* Line number for start of include code */
  1145.     public $declare_classcode;   /* any extends/implements code */
  1146.     public $declare_classln;     /* Line number for start of class declaration code */
  1147.     public $error;             /* Code to execute when an error is seen */
  1148.     public $errorln;            /* Line number for start of error code */
  1149.     public $overflow;          /* Code to execute on a stack overflow */
  1150.     public $overflowln;         /* Line number for start of overflow code */
  1151.     public $failure;           /* Code to execute on parser failure */
  1152.     public $failureln;          /* Line number for start of failure code */
  1153.     public $accept;            /* Code to execute when the parser excepts */
  1154.     public $acceptln;           /* Line number for the start of accept code */
  1155.     public $extracode;         /* Code appended to the generated file */
  1156.     public $extracodeln;        /* Line number for the start of the extra code */
  1157.     public $tokendest;         /* Code to execute to destroy token data */
  1158.     public $tokendestln;        /* Line number for token destroyer code */
  1159.     public $vardest;           /* Code for the default non-terminal destructor */
  1160.     public $vardestln;          /* Line number for default non-term destructor code*/
  1161.     public $filename;          /* Name of the input file */
  1162.     public $filenosuffix;   /* Name of the input file without its extension */
  1163.     public $outname;           /* Name of the current output file */
  1164.     public $tokenprefix;       /* A prefix added to token names in the .h file */
  1165.     public $nconflict;           /* Number of parsing conflicts */
  1166.     public $tablesize;           /* Size of the parse tables */
  1167.     public $basisflag;           /* Prpublic $only basis configurations */
  1168.     public $has_fallback;        /* True if any %fallback is seen in the grammer */
  1169.     public $argv0;             /* Name of the program */
  1170.  
  1171.     /* Find a precedence symbol of every rule in the grammar.
  1172.      * 
  1173.      * Those rules which have a precedence symbol coded in the input
  1174.      * grammar using the "[symbol]" construct will already have the
  1175.      * rp->precsym field filled.  Other rules take as their precedence
  1176.      * symbol the first RHS symbol with a defined precedence.  If there
  1177.      * are not RHS symbols with a defined precedence, the precedence
  1178.      * symbol field is left blank.
  1179.      */
  1180.     function FindRulePrecedences()
  1181.     {
  1182.         for ($rp $this->rule$rp$rp $rp->next{
  1183.             if ($rp->precsym === 0{
  1184.                 for ($i = 0; $i $rp->nrhs && $rp->precsym === 0; $i++{
  1185.                     $sp $rp->rhs[$i];
  1186.                     if ($sp->type == LemonSymbol::MULTITERMINAL{
  1187.                         for ($j = 0; $j $sp->nsubsym; $j++{
  1188.                             if ($sp->subsym[$j]->prec >= 0{
  1189.                                 $rp->precsym = $sp->subsym[$j];
  1190.                                 break;
  1191.                             }
  1192.                         }
  1193.                     elseif ($sp->prec >= 0{
  1194.                         $rp->precsym = $rp->rhs[$i];
  1195.                     }
  1196.                 }
  1197.             }
  1198.         }
  1199.     }
  1200.  
  1201.     /* Find all nonterminals which will generate the empty string.
  1202.      * Then go back and compute the first sets of every nonterminal.
  1203.      * The first set is the set of all terminal symbols which can begin
  1204.      * a string generated by that nonterminal.
  1205.      */
  1206.     function FindFirstSets()
  1207.     {
  1208.         for ($i = 0; $i $this->nsymbol$i++{
  1209.             $this->symbols[$i]->lambda = false;
  1210.         }
  1211.         for($i $this->nterminal$i $this->nsymbol$i++{
  1212.             $this->symbols[$i]->firstset = array();
  1213.         }
  1214.  
  1215.         /* First compute all lambdas */
  1216.         do{
  1217.             $progress = 0;
  1218.             for ($rp $this->rule$rp$rp $rp->next{
  1219.                 if ($rp->lhs->lambda{
  1220.                     continue;
  1221.                 }
  1222.                 for ($i = 0; $i $rp->nrhs; $i++{
  1223.                     $sp $rp->rhs[$i];
  1224.                     if ($sp->type != LemonSymbol::TERMINAL || $sp->lambda === false{
  1225.                         break;
  1226.                     }
  1227.                 }
  1228.                 if ($i === $rp->nrhs{
  1229.                     $rp->lhs->lambda = true;
  1230.                     $progress = 1;
  1231.                 }
  1232.             }
  1233.         while ($progress);
  1234.  
  1235.         /* Now compute all first sets */
  1236.         do {
  1237.             $progress = 0;
  1238.             for ($rp $this->rule$rp$rp $rp->next{
  1239.                 $s1 $rp->lhs;
  1240.                 for ($i = 0; $i $rp->nrhs; $i++{
  1241.                     $s2 $rp->rhs[$i];
  1242.                     if ($s2->type == LemonSymbol::TERMINAL{
  1243.                         //progress += SetAdd(s1->firstset,s2->index);
  1244.                         $progress += isset($s1->firstset[$s2->index]? 0 : 1;
  1245.                         $s1->firstset[$s2->index= 1;
  1246.                         break;
  1247.                     elseif ($s2->type == LemonSymbol::MULTITERMINAL{
  1248.                         for ($j = 0; $j $s2->nsubsym; $j++{
  1249.                             //progress += SetAdd(s1->firstset,s2->subsym[j]->index);
  1250.                             $progress += isset($s1->firstset[$s2->subsym[$j]->index]? 0 : 1;
  1251.                             $s1->firstset[$s2->subsym[$j]->index= 1;
  1252.                         }
  1253.                         break;
  1254.                     elseif ($s1 === $s2{
  1255.                         if ($s1->lambda === false{
  1256.                             break;
  1257.                         }
  1258.                     else {
  1259.                         //progress += SetUnion(s1->firstset,s2->firstset);
  1260.                         $test array_diff_key($s2->firstset$s1->firstset);
  1261.                         if (count($test)) {
  1262.                             $progress++;
  1263.                             $s1->firstset += $test;
  1264.                         }
  1265.                         if ($s2->lambda === false{
  1266.                             break;
  1267.                         }
  1268.                     }
  1269.                 }
  1270.             }
  1271.         while ($progress);
  1272.     }
  1273.  
  1274.     /** Compute all LR(0) states for the grammar.  Links
  1275.      * are added to between some states so that the LR(1) follow sets
  1276.      * can be computed later.
  1277.      */
  1278.     function FindStates()
  1279.     {
  1280.         LemonConfig::Configlist_init();
  1281.     
  1282.         /* Find the start symbol */
  1283.         if ($this->start{
  1284.             $sp = LemonSymbol::Symbol_find($this->start);
  1285.             if ($sp == 0{
  1286.                 Lemon::ErrorMsg($this->filename0,
  1287.                     "The specified start symbol \"%s\" is not " .
  1288.                     "in a nonterminal of the grammar.  \"%s\" will be used as the start " .
  1289.                     "symbol instead."$this->start$this->rule->lhs->name);
  1290.                 $this->errorcnt++;
  1291.                 $sp $this->rule->lhs;
  1292.             }
  1293.         else {
  1294.             $sp $this->rule->lhs;
  1295.         }
  1296.     
  1297.         /* Make sure the start symbol doesn't occur on the right-hand side of
  1298.         ** any rule.  Report an error if it does.  (YACC would generate a new
  1299.         ** start symbol in this case.) */
  1300.         for ($rp $this->rule$rp$rp $rp->next{
  1301.             for ($i = 0; $i $rp->nrhs; $i++{
  1302.                 if ($rp->rhs[$i]->type == LemonSymbol::MULTITERMINAL{
  1303.                     foreach ($rp->rhs[$i]->subsym as $subsp{
  1304.                         if ($subsp === $sp{
  1305.                             Lemon::ErrorMsg($this->filename0,
  1306.                                 "The start symbol \"%s\" occurs on the " .
  1307.                                 "right-hand side of a rule. This will result in a parser which " .
  1308.                                 "does not work properly."$sp->name);
  1309.                             $this->errorcnt++;
  1310.                         }
  1311.                     }
  1312.                 elseif ($rp->rhs[$i=== $sp{
  1313.                     Lemon::ErrorMsg($this->filename0,
  1314.                         "The start symbol \"%s\" occurs on the " .
  1315.                         "right-hand side of a rule. This will result in a parser which " .
  1316.                         "does not work properly."$sp->name);
  1317.                     $this->errorcnt++;
  1318.                 }
  1319.             }
  1320.         }
  1321.     
  1322.         /* The basis configuration set for the first state
  1323.         ** is all rules which have the start symbol as their
  1324.         ** left-hand side */
  1325.         for ($rp $sp->rule; $rp$rp $rp->nextlhs{
  1326.             $newcfp = LemonConfig::Configlist_addbasis($rp0);
  1327.             $newcfp->fws[0= 1;
  1328.         }
  1329.     
  1330.         /* Compute the first state.  All other states will be
  1331.         ** computed automatically during the computation of the first one.
  1332.         ** The returned pointer to the first state is not used. */
  1333.         $newstp = array();
  1334.         $newstp $this->getstate();
  1335.         if (is_array($newstp)) {
  1336.             $this->buildshifts($newstp[0])/* Recursively compute successor states */
  1337.         }
  1338.     }
  1339.  
  1340.     /**
  1341.      * @return LemonState 
  1342.      */
  1343.     private function getstate()
  1344.     {
  1345.         /* Extract the sorted basis of the new state.  The basis was constructed
  1346.         ** by prior calls to "Configlist_addbasis()". */
  1347.         LemonConfig::Configlist_sortbasis();
  1348.         $bp = LemonConfig::Configlist_basis();
  1349.     
  1350.         /* Get a state with the same basis */
  1351.         $stp = LemonState::State_find($bp);
  1352.         if ($stp{
  1353.             /* A state with the same basis already exists!  Copy all the follow-set
  1354.             ** propagation links from the state under construction into the
  1355.             ** preexisting state, then return a pointer to the preexisting state */
  1356.             for($x $bp$y $stp->bp; $x && $y$x $x->bp$y $y->bp{
  1357.                 LemonPlink::Plink_copy($y->bplp$x->bplp);
  1358.                 LemonPlink::Plink_delete($x->fplp);
  1359.                 $x->fplp = $x->bplp = 0;
  1360.             }
  1361.             $cfp = LemonConfig::Configlist_return();
  1362.             LemonConfig::Configlist_eat($cfp);
  1363.         else {
  1364.             /* This really is a new state.  Construct all the details */
  1365.             LemonConfig::Configlist_closure($this);    /* Compute the configuration closure */
  1366.             LemonConfig::Configlist_sort();           /* Sort the configuration closure */
  1367.             $cfp = LemonConfig::Configlist_return();   /* Get a pointer to the config list */
  1368.             $stp = new LemonState;           /* A new state structure */
  1369.             $stp->bp = $bp;                /* Remember the configuration basis */
  1370.             $stp->cfp = $cfp;              /* Remember the configuration closure */
  1371.             $stp->statenum = $this->nstate++; /* Every state gets a sequence number */
  1372.             $stp->ap = 0;                 /* No actions, yet. */
  1373.             LemonState::State_insert($stp$stp->bp);   /* Add to the state table */
  1374.             // this can't work, recursion is too deep, move it into FindStates()
  1375.             //$this->buildshifts($stp);       /* Recursively compute successor states */
  1376.             return array($stp);
  1377.         }
  1378.         return $stp;
  1379.     }
  1380.  
  1381.     /**
  1382.      * Construct all successor states to the given state.  A "successor"
  1383.      * state is any state which can be reached by a shift action.
  1384.      * @param LemonData 
  1385.      * @param LemonState The state from which successors are computed
  1386.      */
  1387.     private function buildshifts(LemonState $stp)
  1388.     {
  1389. //    struct config *cfp;  /* For looping thru the config closure of "stp" */
  1390. //    struct config *bcfp; /* For the inner loop on config closure of "stp" */
  1391. //    struct config *new;  /* */
  1392. //    struct symbol *sp;   /* Symbol following the dot in configuration "cfp" */
  1393. //    struct symbol *bsp;  /* Symbol following the dot in configuration "bcfp" */
  1394. //    struct state *newstp; /* A pointer to a successor state */
  1395.     
  1396.         /* Each configuration becomes complete after it contibutes to a successor
  1397.         ** state.  Initially, all configurations are incomplete */
  1398.         $cfp $stp->cfp;
  1399.         for ($cfp $stp->cfp; $cfp$cfp $cfp->next{
  1400.             $cfp->status = LemonConfig::INCOMPLETE;
  1401.         }
  1402.     
  1403.         /* Loop through all configurations of the state "stp" */
  1404.         for ($cfp $stp->cfp; $cfp$cfp $cfp->next{
  1405.             if ($cfp->status == LemonConfig::COMPLETE{
  1406.                 continue;    /* Already used by inner loop */
  1407.             }
  1408.             if ($cfp->dot >= $cfp->rp->nrhs{
  1409.                 continue;  /* Can't shift this config */
  1410.             }
  1411.             LemonConfig::Configlist_reset();                      /* Reset the new config set */
  1412.             $sp $cfp->rp->rhs[$cfp->dot];             /* Symbol after the dot */
  1413.     
  1414.             /* For every configuration in the state "stp" which has the symbol "sp"
  1415.             ** following its dot, add the same configuration to the basis set under
  1416.             ** construction but with the dot shifted one symbol to the right. */
  1417.             $bcfp $cfp;
  1418.             for ($bcfp $cfp$bcfp$bcfp $bcfp->next{
  1419.                 if ($bcfp->status == LemonConfig::COMPLETE{
  1420.                     continue;    /* Already used */
  1421.                 }
  1422.                 if ($bcfp->dot >= $bcfp->rp->nrhs{
  1423.                     continue; /* Can't shift this one */
  1424.                 }
  1425.                 $bsp $bcfp->rp->rhs[$bcfp->dot];           /* Get symbol after dot */
  1426.                 if (!LemonSymbol::same_symbol($bsp$sp)) {
  1427.                     continue;      /* Must be same as for "cfp" */
  1428.                 }
  1429.                 $bcfp->status = LemonConfig::COMPLETE;             /* Mark this config as used */
  1430.                 $new = LemonConfig::Configlist_addbasis($bcfp->rp$bcfp->dot + 1);
  1431.                 LemonPlink::Plink_add($new->bplp$bcfp);
  1432.             }
  1433.  
  1434.             /* Get a pointer to the state described by the basis configuration set
  1435.             ** constructed in the preceding loop */
  1436.             $newstp $this->getstate();
  1437.             if (is_array($newstp)) {
  1438.                 $this->buildshifts($newstp[0])/* Recursively compute successor states */
  1439.                 $newstp $newstp[0];
  1440.             }
  1441.  
  1442.             /* The state "newstp" is reached from the state "stp" by a shift action
  1443.             ** on the symbol "sp" */
  1444.             if ($sp->type == LemonSymbol::MULTITERMINAL{
  1445.                 for($i = 0; $i $sp->nsubsym; $i++{
  1446.                     LemonAction::Action_add($stp->apLemonAction::SHIFT$sp->subsym[$i],
  1447.                                             $newstp);
  1448.                 }
  1449.             else {
  1450.                 LemonAction::Action_add($stp->apLemonAction::SHIFT$sp$newstp);
  1451.             }
  1452.         }
  1453.     }
  1454.  
  1455.     /**
  1456.      * Construct the propagation links
  1457.      */
  1458.     function FindLinks()
  1459.     {
  1460.         /* Housekeeping detail:
  1461.         ** Add to every propagate link a pointer back to the state to
  1462.         ** which the link is attached. */
  1463.         foreach ($this->sorted as $info{
  1464.             $info->key->stp = $info->data;
  1465.         }
  1466.         
  1467.         /* Convert all backlinks into forward links.  Only the forward
  1468.         ** links are used in the follow-set computation. */
  1469.         for ($i = 0; $i $this->nstate$i++{
  1470.             $stp $this->sorted[$i];
  1471.             for ($cfp $stp->data->cfp; $cfp$cfp $cfp->next{
  1472.                 for ($plp $cfp->bplp; $plp$plp $plp->next{
  1473.                     $other $plp->cfp;
  1474.                     LemonPlink::Plink_add($other->fplp$cfp);
  1475.                 }
  1476.             }
  1477.         }
  1478.     }
  1479.  
  1480.     /**
  1481.      * Compute the reduce actions, and resolve conflicts.
  1482.      */
  1483.     function FindActions()
  1484.     {
  1485.         /* Add all of the reduce actions 
  1486.         ** A reduce action is added for each element of the followset of
  1487.         ** a configuration which has its dot at the extreme right.
  1488.         */
  1489.         for ($i = 0; $i $this->nstate$i++{   /* Loop over all states */
  1490.             $stp $this->sorted[$i]->data;
  1491.             for ($cfp $stp->cfp; $cfp$cfp $cfp->next{
  1492.                 /* Loop over all configurations */
  1493.                 if ($cfp->rp->nrhs == $cfp->dot{        /* Is dot at extreme right? */
  1494.                     for ($j = 0; $j $this->nterminal$j++{
  1495.                         if (isset($cfp->fws[$j])) {
  1496.                             /* Add a reduce action to the state "stp" which will reduce by the
  1497.                             ** rule "cfp->rp" if the lookahead symbol is "$this->symbols[j]" */
  1498.                             LemonAction::Action_add($stp->apLemonAction::REDUCE,
  1499.                                                     $this->symbols[$j]$cfp->rp);
  1500.                         }
  1501.                     }
  1502.                 }
  1503.             }
  1504.         }
  1505.  
  1506.         /* Add the accepting token */
  1507.         if ($this->start instanceof LemonSymbol{
  1508.             $sp = LemonSymbol::Symbol_find($this->start);
  1509.             if ($sp === 0{
  1510.                 $sp $this->rule->lhs;
  1511.             }
  1512.         else {
  1513.             $sp $this->rule->lhs;
  1514.         }
  1515.         /* Add to the first state (which is always the starting state of the
  1516.         ** finite state machine) an action to ACCEPT if the lookahead is the
  1517.         ** start nonterminal.  */
  1518.         LemonAction::Action_add($this->sorted[0]->data->apLemonAction::ACCEPT$sp0);
  1519.     
  1520.         /* Resolve conflicts */
  1521.         for ($i = 0; $i $this->nstate$i++{
  1522.     //    struct action *ap, *nap;
  1523.     //    struct state *stp;
  1524.             $stp $this->sorted[$i]->data;
  1525.             if (!$stp->ap{
  1526.                 throw new Exception('state has no actions associated');
  1527.             }
  1528.             $stp->ap = LemonAction::Action_sort($stp->ap);
  1529.             for ($ap $stp->ap; $ap !== 0 && $ap->next !== 0; $ap $ap->next{
  1530.                 for ($nap $ap->next; $nap !== 0 && $nap->sp === $ap->sp ; $nap $nap->next{
  1531.                     /* The two actions "ap" and "nap" have the same lookahead.
  1532.                     ** Figure out which one should be used */
  1533.                     $this->nconflict += $this->resolve_conflict($ap$nap$this->errsym);
  1534.                 }
  1535.             }
  1536.         }
  1537.     
  1538.         /* Report an error for each rule that can never be reduced. */
  1539.         for ($rp $this->rule$rp$rp $rp->next{
  1540.             $rp->canReduce = false;
  1541.         }
  1542.         for ($i = 0; $i $this->nstate$i++{
  1543.             for ($ap $this->sorted[$i]->data->ap; $ap !== 0; $ap $ap->next{
  1544.                 if ($ap->type == LemonAction::REDUCE{
  1545.                     $ap->x->canReduce = true;
  1546.                 }
  1547.             }
  1548.         }
  1549.         for ($rp $this->rule$rp !== 0; $rp $rp->next{
  1550.             if ($rp->canReduce{
  1551.                 continue;
  1552.             }
  1553.             Lemon::ErrorMsg($this->filename$rp->ruleline"This rule can not be reduced.\n");
  1554.             $this->errorcnt++;
  1555.         }
  1556.     }
  1557.  
  1558.     /** Resolve a conflict between the two given actions.  If the
  1559.      * conflict can't be resolve, return non-zero.
  1560.      *
  1561.      * NO LONGER TRUE:
  1562.      *   To resolve a conflict, first look to see if either action
  1563.      *   is on an error rule.  In that case, take the action which
  1564.      *   is not associated with the error rule.  If neither or both
  1565.      *   actions are associated with an error rule, then try to
  1566.      *   use precedence to resolve the conflict.
  1567.      *
  1568.      * If either action is a SHIFT, then it must be apx.  This
  1569.      * function won't work if apx->type==REDUCE and apy->type==SHIFT.
  1570.      * @param LemonAction 
  1571.      * @param LemonAction 
  1572.      * @param LemonSymbol|nullThe error symbol (if defined.  NULL otherwise)
  1573.      */
  1574.     function resolve_conflict($apx$apy$errsym)
  1575.     {
  1576.         $errcnt = 0;
  1577.         if ($apx->sp !== $apy->sp{
  1578.             throw new Exception('no conflict but resolve_conflict called');
  1579.         }
  1580.         if ($apx->type == LemonAction::SHIFT && $apy->type == LemonAction::REDUCE{
  1581.             $spx $apx->sp;
  1582.             $spy $apy->x->precsym;
  1583.             if ($spy === 0 || $spx->prec < 0 || $spy->prec < 0{
  1584.                 /* Not enough precedence information. */
  1585.                 $apy->type = LemonAction::CONFLICT;
  1586.                 $errcnt++;
  1587.             elseif ($spx->prec > $spy->prec{    /* Lower precedence wins */
  1588.                 $apy->type = LemonAction::RD_RESOLVED;
  1589.             elseif ($spx->prec < $spy->prec{
  1590.                 $apx->type = LemonAction::SH_RESOLVED;
  1591.             elseif ($spx->prec === $spy->prec && $spx->assoc == LemonSymbol::RIGHT{
  1592.                 /* Use operator */
  1593.                 $apy->type = LemonAction::RD_RESOLVED;                       /* associativity */
  1594.             elseif ($spx->prec === $spy->prec && $spx->assoc == LemonSymbol::LEFT{
  1595.                 /* to break tie */
  1596.                 $apx->type = LemonAction::SH_RESOLVED;
  1597.             else {
  1598.                 if ($spx->prec !== $spy->prec || $spx->assoc !== LemonSymbol::NONE{
  1599.                     throw new Exception('$spx->prec !== $spy->prec || $spx->assoc !== LemonSymbol::NONE');
  1600.                 }
  1601.                 $apy->type = LemonAction::CONFLICT;
  1602.                 $errcnt++;
  1603.             }
  1604.         elseif ($apx->type == LemonAction::REDUCE && $apy->type == LemonAction::REDUCE{
  1605.             $spx $apx->x->precsym;
  1606.             $spy $apy->x->precsym;
  1607.             if ($spx === 0 || $spy === 0 || $spx->prec < 0 ||
  1608.                   $spy->prec < 0 || $spx->prec === $spy->prec{
  1609.                 $apy->type = LemonAction::CONFLICT;
  1610.                 $errcnt++;
  1611.             elseif ($spx->prec > $spy->prec{
  1612.                 $apy->type = LemonAction::RD_RESOLVED;
  1613.             elseif ($spx->prec < $spy->prec{
  1614.                 $apx->type = LemonAction::RD_RESOLVED;
  1615.             }
  1616.         else {
  1617.             if ($apx->type!== LemonAction::SH_RESOLVED &&
  1618.                 $apx->type!== LemonAction::RD_RESOLVED &&
  1619.                 $apx->type!== LemonAction::CONFLICT &&
  1620.                 $apy->type!== LemonAction::SH_RESOLVED &&
  1621.                 $apy->type!== LemonAction::RD_RESOLVED &&
  1622.                 $apy->type!== LemonAction::CONFLICT{
  1623.                 throw new Exception('$apx->type!== LemonAction::SH_RESOLVED &&
  1624.                 $apx->type!== LemonAction::RD_RESOLVED &&
  1625.                 $apx->type!== LemonAction::CONFLICT &&
  1626.                 $apy->type!== LemonAction::SH_RESOLVED &&
  1627.                 $apy->type!== LemonAction::RD_RESOLVED &&
  1628.                 $apy->type!== LemonAction::CONFLICT');
  1629.             }
  1630.             /* The REDUCE/SHIFT case cannot happen because SHIFTs come before
  1631.             ** REDUCEs on the list.  If we reach this point it must be because
  1632.             ** the parser conflict had already been resolved. */
  1633.         }
  1634.         return $errcnt;
  1635.     }
  1636.  
  1637.     /**
  1638.      * Reduce the size of the action tables, if possible, by making use
  1639.      * of defaults.
  1640.      *
  1641.      * In this version, we take the most frequent REDUCE action and make
  1642.      * it the default.
  1643.      */
  1644.     function CompressTables()
  1645.     {
  1646.         for ($i = 0; $i $this->nstate$i++{
  1647.             $stp $this->sorted[$i]->data;
  1648.             $nbest = 0;
  1649.             $rbest = 0;
  1650.  
  1651.             for ($ap $stp->ap; $ap$ap $ap->next{
  1652.                 if ($ap->type != LemonAction::REDUCE{
  1653.                     continue;
  1654.                 }
  1655.                 $rp $ap->x;
  1656.                 if ($rp === $rbest{
  1657.                     continue;
  1658.                 }
  1659.                 $n = 1;
  1660.                 for ($ap2 $ap->next; $ap2$ap2 $ap2->next{
  1661.                     if ($ap2->type != LemonAction::REDUCE{
  1662.                         continue;
  1663.                     }
  1664.                     $rp2 $ap2->x;
  1665.                     if ($rp2 === $rbest{
  1666.                         continue;
  1667.                     }
  1668.                     if ($rp2 === $rp{
  1669.                         $n++;
  1670.                     }
  1671.                 }
  1672.                 if ($n $nbest{
  1673.                     $nbest $n;
  1674.                     $rbest $rp;
  1675.                 }
  1676.             }
  1677.  
  1678.             /* Do not make a default if the number of rules to default
  1679.             ** is not at least 1 */
  1680.             if ($nbest < 1{
  1681.                 continue;
  1682.             }
  1683.  
  1684.  
  1685.             /* Combine matching REDUCE actions into a single default */
  1686.             for ($ap $stp->ap; $ap$ap $ap->next{
  1687.                 if ($ap->type == LemonAction::REDUCE && $ap->x === $rbest{
  1688.                     break;
  1689.                 }
  1690.             }
  1691.             if ($ap === 0{
  1692.                 throw new Exception('$ap is not an object');
  1693.             }
  1694.             $ap->sp = LemonSymbol::Symbol_new("{default}");
  1695.             for ($ap $ap->next; $ap$ap $ap->next{
  1696.                 if ($ap->type == LemonAction::REDUCE && $ap->x === $rbest{
  1697.                     $ap->type = LemonAction::NOT_USED;
  1698.                 }
  1699.             }
  1700.             $stp->ap = LemonAction::Action_sort($stp->ap);
  1701.         }
  1702.     }
  1703.  
  1704.     /**
  1705.      * Renumber and resort states so that states with fewer choices
  1706.      * occur at the end.  Except, keep state 0 as the first state.
  1707.      */
  1708.     function ResortStates()
  1709.     {
  1710.         for ($i = 0; $i $this->nstate$i++{
  1711.             $stp $this->sorted[$i]->data;
  1712.             $stp->nTknAct = $stp->nNtAct = 0;
  1713.             $stp->iDflt = $this->nstate $this->nrule;
  1714.             $stp->iTknOfst = NO_OFFSET;
  1715.             $stp->iNtOfst = NO_OFFSET;
  1716.             for ($ap $stp->ap; $ap$ap $ap->next{
  1717.                 if ($this->compute_action($ap>= 0{
  1718.                     if ($ap->sp->index < $this->nterminal{
  1719.                         $stp->nTknAct++;
  1720.                     elseif ($ap->sp->index < $this->nsymbol{
  1721.                         $stp->nNtAct++;
  1722.                     else {
  1723.                         $stp->iDflt = $this->compute_action($ap);
  1724.                     }
  1725.                 }
  1726.             }
  1727.             $this->sorted[$i$stp;
  1728.         }
  1729.         $save $this->sorted[0];
  1730.         unset($this->sorted[0]);
  1731.         usort($this->sortedarray('LemonState''stateResortCompare'));
  1732.         array_unshift($this->sorted$save);
  1733.         for($i = 0; $i $this->nstate$i++{
  1734.             $this->sorted[$i]->statenum = $i;
  1735.         }
  1736.     }
  1737.  
  1738.     /**
  1739.      * Given an action, compute the integer value for that action
  1740.      * which is to be put in the action table of the generated machine.
  1741.      * Return negative if no action should be generated.
  1742.      * @param LemonAction 
  1743.      */
  1744.     function compute_action($ap)
  1745.     {
  1746.         switch ($ap->type{
  1747.             case LemonAction::SHIFT:
  1748.                 $act $ap->x->statenum;
  1749.                 break;
  1750.             case LemonAction::REDUCE:
  1751.                 $act $ap->x->index + $this->nstate;
  1752.                 break;
  1753.             case LemonAction::ERROR:
  1754.                 $act $this->nstate $this->nrule;
  1755.                 break;
  1756.             case LemonAction::ACCEPT:
  1757.                 $act $this->nstate $this->nrule + 1;
  1758.                 break;
  1759.             default:
  1760.                 $act = -1;
  1761.                 break;
  1762.         }
  1763.         return $act;
  1764.     }
  1765.  
  1766.     /**
  1767.      * Generate the "y.output" log file
  1768.      */
  1769.     function ReportOutput()
  1770.     {
  1771.         $fp fopen($this->filenosuffix ".out""wb");
  1772.         if (!$fp{
  1773.             return;
  1774.         }
  1775.         for ($i = 0; $i $this->nstate$i++{
  1776.             $stp $this->sorted[$i];
  1777.             fprintf($fp"State %d:\n"$stp->statenum);
  1778.             if ($this->basisflag{
  1779.                 $cfp $stp->bp;
  1780.             else {
  1781.                 $cfp $stp->cfp;
  1782.             }
  1783.             while ($cfp{
  1784.                 if ($cfp->dot == $cfp->rp->nrhs{
  1785.                     $buf sprintf('(%d)'$cfp->rp->index);
  1786.                     fprintf($fp'    %5s '$buf);
  1787.                 else {
  1788.                     fwrite($fp,'          ');
  1789.                 }
  1790.                 $cfp->ConfigPrint($fp);
  1791.                 fwrite($fp"\n");
  1792.                 if (0{
  1793.                     //SetPrint(fp,cfp->fws,$this);
  1794.                     //PlinkPrint(fp,cfp->fplp,"To  ");
  1795.                     //PlinkPrint(fp,cfp->bplp,"From");
  1796.                 }
  1797.                 if ($this->basisflag{
  1798.                     $cfp $cfp->bp;
  1799.                 else {
  1800.                     $cfp $cfp->next;
  1801.                 }
  1802.             }
  1803.             fwrite($fp"\n");
  1804.             for ($ap $stp->ap; $ap$ap $ap->next{
  1805.                 if ($ap->PrintAction($fp30)) {
  1806.                     fprintf($fp,"\n");
  1807.                 }
  1808.             }
  1809.             fwrite($fp,"\n");
  1810.         }
  1811.         fclose($fp);
  1812.     }
  1813.  
  1814.     /* The next function finds the template file and opens it, returning
  1815.     ** a pointer to the opened file. */
  1816.     private function tplt_open()
  1817.     {
  1818.         $templatename dirname(__FILE__"Lempar.php";
  1819.         $buf $this->filenosuffix '.lt';
  1820.         if (file_exists($buf&& is_readable($buf)) {
  1821.             $tpltname $buf;
  1822.         elseif (file_exists($templatename&& is_readable($templatename)) {
  1823.             $tpltname $templatename;
  1824.         elseif ($fp @fopen($templatename'rb'true)) {
  1825.             return $fp;
  1826.         }
  1827.         if (!isset($tpltname)) {
  1828.             echo "Can't find the parser driver template file \"%s\".\n",
  1829.                 $templatename;
  1830.             $this->errorcnt++;
  1831.             return 0;
  1832.         }
  1833.         $in @fopen($tpltname,"rb");
  1834.         if (!$in{
  1835.             printf("Can't open the template file \"%s\".\n"$tpltname);
  1836.             $this->errorcnt++;
  1837.             return 0;
  1838.         }
  1839.         return $in;
  1840.     }
  1841.  
  1842. #define LINESIZE 1000
  1843.     /**#@+
  1844.      * The next cluster of routines are for reading the template file
  1845.      * and writing the results to the generated parser
  1846.      */
  1847.     /**
  1848.      * The first function transfers data from "in" to "out" until
  1849.      * a line is seen which begins with "%%".  The line number is
  1850.      * tracked.
  1851.      *
  1852.      * if name!=0, then any word that begin with "Parse" is changed to
  1853.      * begin with *name instead.
  1854.      */
  1855.     private function tplt_xfer($name$in$out&$lineno)
  1856.     {
  1857.         while (($line fgets($in1024)) && ($line[0!= '%' || $line[1!= '%')) {
  1858.             $lineno++;
  1859.             $iStart = 0;
  1860.             if ($name{
  1861.                 for ($i = 0; $i strlen($line)$i++{
  1862.                     if ($line[$i== 'P' && substr($line$i5== "Parse"
  1863.                           && ($i === 0 || preg_match('/[^a-zA-Z]/'$line[$i - 1]))) {
  1864.                         if ($i $iStart{
  1865.                             fwrite($outsubstr($line$iStart$i $iStart));
  1866.                         }
  1867.                         fwrite($out$name);
  1868.                         $i += 4;
  1869.                         $iStart $i + 1;
  1870.                     }
  1871.                 }
  1872.             }
  1873.             fwrite($outsubstr($line$iStart));
  1874.         }
  1875.     }
  1876.  
  1877.     /**
  1878.      * Print a #line directive line to the output file.
  1879.      */
  1880.     private function tplt_linedir($out$lineno$filename)
  1881.     {
  1882.         fwrite($out'#line ' $lineno ' "' $filename "\"\n");
  1883.     }
  1884.  
  1885.     /**
  1886.      * Print a string to the file and keep the linenumber up to date
  1887.      */
  1888.     private function tplt_print($out$str$strln&$lineno)
  1889.     {
  1890.         if ($str == ''{
  1891.             return;
  1892.         }
  1893.         $this->tplt_linedir($out$strln$this->filename);
  1894.         $lineno++;
  1895.         fwrite($out$str);
  1896.         $lineno += count(explode("\n"$str)) - 1;
  1897.         $this->tplt_linedir($out$lineno + 2$this->outname);
  1898.         $lineno += 2;
  1899.     }
  1900.     /**#@-*/
  1901.  
  1902.     /**
  1903.      * Compute all followsets.
  1904.      *
  1905.      * A followset is the set of all symbols which can come immediately
  1906.      * after a configuration.
  1907.      */
  1908.     function FindFollowSets()
  1909.     {
  1910.         for ($i = 0; $i $this->nstate$i++{
  1911.             for ($cfp $this->sorted[$i]->data->cfp; $cfp$cfp $cfp->next{
  1912.                 $cfp->status = LemonConfig::INCOMPLETE;
  1913.             }
  1914.         }
  1915.         
  1916.         do {
  1917.             $progress = 0;
  1918.             for ($i = 0; $i $this->nstate$i++{
  1919.                 for ($cfp $this->sorted[$i]->data->cfp; $cfp$cfp $cfp->next{
  1920.                     if ($cfp->status == LemonConfig::COMPLETE{
  1921.                         continue;
  1922.                     }
  1923.                     for ($plp $cfp->fplp; $plp$plp $plp->next{
  1924.                         $a array_diff_key($cfp->fws$plp->cfp->fws);
  1925.                         if (count($a)) {
  1926.                             $plp->cfp->fws += $a;
  1927.                             $plp->cfp->status = LemonConfig::INCOMPLETE;
  1928.                             $progress = 1;
  1929.                         }
  1930.                     }
  1931.                     $cfp->status = LemonConfig::COMPLETE;
  1932.                 }
  1933.             }
  1934.         while ($progress);
  1935.     }
  1936.  
  1937.     /**
  1938.      * Generate C source code for the parser
  1939.      * @param int Output in makeheaders format if true
  1940.      */
  1941.     function ReportTable($mhflag)
  1942.     {
  1943. //        FILE *out, *in;
  1944. //        char line[LINESIZE];
  1945. //        int  lineno;
  1946. //        struct state *stp;
  1947. //        struct action *ap;
  1948. //        struct rule *rp;
  1949. //        struct acttab *pActtab;
  1950. //        int i, j, n;
  1951. //        char *name;
  1952. //        int mnTknOfst, mxTknOfst;
  1953. //        int mnNtOfst, mxNtOfst;
  1954. //        struct axset *ax;
  1955.         
  1956.         $in $this->tplt_open();
  1957.         if (!$in{
  1958.             return;
  1959.         }
  1960.         $out fopen($this->filenosuffix ".php""wb");
  1961.         if (!$out{
  1962.             fclose($in);
  1963.             return;
  1964.         }
  1965.         $this->outname $this->filenosuffix ".php";
  1966.         $lineno = 1;
  1967.         $this->tplt_xfer($this->name$in$out$lineno);
  1968.         
  1969.         /* Generate the include code, if any */
  1970.         $this->tplt_print($out$this->include_code$this->includeln$lineno);
  1971.         $this->tplt_xfer($this->name$in$out$lineno);
  1972.  
  1973.         /* Generate the class declaration code */
  1974.         $this->tplt_print($out$this->declare_classcode$this->declare_classln,
  1975.             $lineno);
  1976.         $this->tplt_xfer($this->name$in$out$lineno);
  1977.  
  1978.         /* Generate the internal parser class include code, if any */
  1979.         $this->tplt_print($out$this->include_classcode$this->include_classln,
  1980.             $lineno);
  1981.         $this->tplt_xfer($this->name$in$out$lineno);
  1982.  
  1983.         /* Generate #defines for all tokens */
  1984.         //if ($mhflag) {
  1985.             //fprintf($out, "#if INTERFACE\n");
  1986.             $lineno++;
  1987.             if ($this->tokenprefix{
  1988.                 $prefix $this->tokenprefix;
  1989.             else {
  1990.                 $prefix '';
  1991.             }
  1992.             for ($i = 1; $i $this->nterminal$i++{
  1993.                 fprintf($out"    const %s%-30s = %2d;\n"$prefix$this->symbols[$i]->name$i);
  1994.                 $lineno++;
  1995.             }
  1996.             //fwrite($out, "#endif\n");
  1997.             $lineno++;
  1998.         //}
  1999.         fwrite($out"    const YY_NO_ACTION = " .
  2000.             ($this->nstate $this->nrule + 2";\n");
  2001.         $lineno++;
  2002.         fwrite($out"    const YY_ACCEPT_ACTION = " .
  2003.             ($this->nstate $this->nrule + 1";\n");
  2004.         $lineno++;
  2005.         fwrite($out"    const YY_ERROR_ACTION = " .
  2006.             ($this->nstate $this->nrule";\n");
  2007.         $lineno++;
  2008.         $this->tplt_xfer($this->name$in$out$lineno);
  2009.         
  2010.         /* Generate the action table and its associates:
  2011.         **
  2012.         **  yy_action[]        A single table containing all actions.
  2013.         **  yy_lookahead[]     A table containing the lookahead for each entry in
  2014.         **                     yy_action.  Used to detect hash collisions.
  2015.         **  yy_shift_ofst[]    For each state, the offset into yy_action for
  2016.         **                     shifting terminals.
  2017.         **  yy_reduce_ofst[]   For each state, the offset into yy_action for
  2018.         **                     shifting non-terminals after a reduce.
  2019.         **  yy_default[]       Default action for each state.
  2020.         */
  2021.  
  2022.         /* Compute the actions on all states and count them up */
  2023.  
  2024.         $ax = array();
  2025.         for ($i = 0; $i $this->nstate$i++{
  2026.             $stp $this->sorted[$i];
  2027.             $ax[$i * 2= array();
  2028.             $ax[$i * 2]['stp'$stp;
  2029.             $ax[$i * 2]['isTkn'= 1;
  2030.             $ax[$i * 2]['nAction'$stp->nTknAct;
  2031.             $ax[$i * 2 + 1= array();
  2032.             $ax[$i * 2 + 1]['stp'$stp;
  2033.             $ax[$i * 2 + 1]['isTkn'= 0;
  2034.             $ax[$i * 2 + 1]['nAction'$stp->nNtAct;
  2035.         }
  2036.         $mxTknOfst $mnTknOfst = 0;
  2037.         $mxNtOfst $mnNtOfst = 0;
  2038.  
  2039.         /* Compute the action table.  In order to try to keep the size of the
  2040.         ** action table to a minimum, the heuristic of placing the largest action
  2041.         ** sets first is used.
  2042.         */
  2043.  
  2044.         usort($axarray('LemonData''axset_compare'));
  2045.         $pActtab = new LemonActtab;
  2046.         for ($i = 0; $i $this->nstate * 2 && $ax[$i]['nAction'> 0; $i++{
  2047.             $stp $ax[$i]['stp'];
  2048.             if ($ax[$i]['isTkn']{
  2049.                 for ($ap $stp->ap; $ap$ap $ap->next{
  2050.                     if ($ap->sp->index >= $this->nterminal{
  2051.                         continue;
  2052.                     }
  2053.                     $action $this->compute_action($ap);
  2054.                     if ($action < 0{
  2055.                         continue;
  2056.                     }
  2057.                     $pActtab->acttab_action($ap->sp->index$action);
  2058.                 }
  2059.                 $stp->iTknOfst = $pActtab->acttab_insert();
  2060.                 if ($stp->iTknOfst < $mnTknOfst{
  2061.                     $mnTknOfst $stp->iTknOfst;
  2062.                 }
  2063.                 if ($stp->iTknOfst > $mxTknOfst{
  2064.                     $mxTknOfst $stp->iTknOfst;
  2065.                 }
  2066.             else {
  2067.                 for ($ap $stp->ap; $ap$ap $ap->next{
  2068.                     if ($ap->sp->index < $this->nterminal{
  2069.                         continue;
  2070.                     }
  2071.                     if ($ap->sp->index == $this->nsymbol{
  2072.                         continue;
  2073.                     }
  2074.                     $action $this->compute_action($ap);
  2075.                     if ($action < 0{
  2076.                         continue;
  2077.                     }
  2078.                     $pActtab->acttab_action($ap->sp->index$action);
  2079.                 }
  2080.                 $stp->iNtOfst = $pActtab->acttab_insert();
  2081.                 if ($stp->iNtOfst < $mnNtOfst{
  2082.                     $mnNtOfst $stp->iNtOfst;
  2083.                 }
  2084.                 if ($stp->iNtOfst > $mxNtOfst{
  2085.                     $mxNtOfst $stp->iNtOfst;
  2086.                 }
  2087.             }
  2088.         }
  2089.         /* Output the yy_action table */
  2090.  
  2091.         fprintf($out"    const YY_SZ_ACTTAB = %d;\n"$pActtab->nAction);
  2092.         $lineno++;
  2093.         fwrite($out"static public \$yy_action = array(\n");
  2094.         $lineno++;
  2095.         $n $pActtab->nAction;
  2096.         for($i $j = 0; $i $n$i++{
  2097.             $action $pActtab->aAction[$i]['action'];
  2098.             if ($action < 0{
  2099.                 $action $this->nsymbol $this->nrule + 2;
  2100.             }
  2101.             // change next line
  2102.             if ($j === 0{
  2103.                 fprintf($out" /* %5d */ "$i);
  2104.             }
  2105.             fprintf($out" %4d,"$action);
  2106.             if ($j == 9 || $i == $n - 1{
  2107.                 fwrite($out"\n");
  2108.                 $lineno++;
  2109.                 $j = 0;
  2110.             else {
  2111.                 $j++;
  2112.             }
  2113.         }
  2114.         fwrite($out"    );\n")$lineno++;
  2115.  
  2116.         /* Output the yy_lookahead table */
  2117.  
  2118.         fwrite($out"    static public \$yy_lookahead = array(\n");
  2119.         $lineno++;
  2120.         for ($i $j = 0; $i $n$i++{
  2121.             $la $pActtab->aAction[$i]['lookahead'];
  2122.             if ($la < 0{
  2123.                 $la $this->nsymbol;
  2124.             }
  2125.             // change next line
  2126.             if ($j === 0{
  2127.                 fprintf($out" /* %5d */ "$i);
  2128.             }
  2129.             fprintf($out" %4d,"$la);
  2130.             if ($j == 9 || $i == $n - 1{
  2131.                 fwrite($out"\n");
  2132.                 $lineno++;
  2133.                 $j = 0;
  2134.             else {
  2135.                 $j++;
  2136.             }
  2137.         }
  2138.         fwrite($out");\n");
  2139.         $lineno++;
  2140.  
  2141.         /* Output the yy_shift_ofst[] table */
  2142.         fprintf($out"    const YY_SHIFT_USE_DFLT = %d;\n"$mnTknOfst - 1);
  2143.         $lineno++;
  2144.         $n $this->nstate;
  2145.         while ($n > 0 && $this->sorted[$n - 1]->iTknOfst == NO_OFFSET{
  2146.             $n--;
  2147.         }
  2148.         fprintf($out"    const YY_SHIFT_MAX = %d;\n"$n - 1);
  2149.         $lineno++;
  2150.         fwrite($out"    static public \$yy_shift_ofst = array(\n");
  2151.         $lineno++;
  2152.         for ($i $j = 0; $i $n$i++{
  2153.             $stp $this->sorted[$i];
  2154.             $ofst $stp->iTknOfst;
  2155.             if ($ofst === NO_OFFSET{
  2156.                 $ofst $mnTknOfst - 1;
  2157.             }
  2158.             // change next line
  2159.             if ($j === 0{
  2160.                 fprintf($out" /* %5d */ "$i);
  2161.             }
  2162.             fprintf($out" %4d,"$ofst);
  2163.             if ($j == 9 || $i == $n - 1{
  2164.                 fwrite($out"\n");
  2165.                 $lineno++;
  2166.                 $j = 0;
  2167.             else {
  2168.                 $j++;
  2169.             }
  2170.         }
  2171.         fwrite($out");\n");
  2172.         $lineno++;
  2173.  
  2174.  
  2175.         /* Output the yy_reduce_ofst[] table */
  2176.  
  2177.         fprintf($out"    const YY_REDUCE_USE_DFLT = %d;\n"$mnNtOfst - 1);
  2178.         $lineno++;
  2179.         $n $this->nstate;
  2180.         while ($n > 0 && $this->sorted[$n - 1]->iNtOfst == NO_OFFSET{
  2181.             $n--;
  2182.         }
  2183.         fprintf($out"    const YY_REDUCE_MAX = %d;\n"$n - 1);
  2184.         $lineno++;
  2185.         fwrite($out"    static public \$yy_reduce_ofst = array(\n");
  2186.         $lineno++;
  2187.         for ($i $j = 0; $i $n$i++{
  2188.             $stp $this->sorted[$i];
  2189.             $ofst $stp->iNtOfst;
  2190.             if ($ofst == NO_OFFSET{
  2191.                 $ofst $mnNtOfst - 1;
  2192.             }
  2193.             // change next line
  2194.             if ($j == 0{
  2195.                 fprintf($out" /* %5d */ "$i);
  2196.             }
  2197.             fprintf($out" %4d,"$ofst);
  2198.             if ($j == 9 || $i == $n - 1{
  2199.                 fwrite($out"\n");
  2200.                 $lineno++;
  2201.                 $j = 0;
  2202.             else {
  2203.                 $j++;
  2204.             }
  2205.         }
  2206.         fwrite($out");\n");
  2207.         $lineno++;
  2208.  
  2209.         /* Output the expected tokens table */
  2210.  
  2211.         fwrite($out"    static public \$yyExpectedTokens = array(\n");
  2212.         $lineno++;
  2213.         for ($i = 0; $i $this->nstate$i++{
  2214.             $stp $this->sorted[$i];
  2215.             fwrite($out"        /* $i */ array(");
  2216.             for ($ap $stp->ap; $ap$ap $ap->next{
  2217.                 if ($ap->sp->index < $this->nterminal{
  2218.                     if ($ap->type == LemonAction::SHIFT ||
  2219.                           $ap->type == LemonAction::REDUCE{
  2220.                         fwrite($out$ap->sp->index . ', ');
  2221.                     }       
  2222.                 }
  2223.             }
  2224.             fwrite($out"),\n");
  2225.             $lineno++;
  2226.         }
  2227.         fwrite($out");\n");
  2228.         $lineno++;
  2229.  
  2230.         /* Output the default action table */
  2231.  
  2232.         fwrite($out"    static public \$yy_default = array(\n");
  2233.         $lineno++;
  2234.         $n $this->nstate;
  2235.         for ($i $j = 0; $i $n$i++{
  2236.             $stp $this->sorted[$i];
  2237.             // change next line
  2238.             if ($j == 0{
  2239.                 fprintf($out" /* %5d */ "$i);
  2240.             }
  2241.             fprintf($out" %4d,"$stp->iDflt);
  2242.             if ($j == 9 || $i == $n - 1{
  2243.                 fprintf($out"\n")$lineno++;
  2244.                 $j = 0;
  2245.             else {
  2246.                 $j++;
  2247.             }
  2248.         }
  2249.         fwrite($out");\n");
  2250.         $lineno++;
  2251.         $this->tplt_xfer($this->name$in$out$lineno);
  2252.  
  2253.         /* Generate the defines */
  2254.         fprintf($out"    const YYNOCODE = %d;\n"$this->nsymbol + 1);
  2255.         $lineno++;
  2256.         if ($this->stacksize{
  2257.             if($this->stacksize <= 0{
  2258.                 Lemon::ErrorMsg($this->filename0,
  2259.                     "Illegal stack size: [%s].  The stack size should be an integer constant.",
  2260.                     $this->stacksize);
  2261.                 $this->errorcnt++;
  2262.                 $this->stacksize "100";
  2263.             }
  2264.             fprintf($out"    const YYSTACKDEPTH = %s;\n"$this->stacksize);
  2265.             $lineno++;
  2266.         else {
  2267.             fwrite($out,"    const YYSTACKDEPTH = 100;\n");
  2268.             $lineno++;
  2269.         }
  2270.         $name $this->name $this->name "Parse";
  2271.         if (isset($this->arg&& strlen($this->arg)) {
  2272.             $this->arg str_replace('$'''$this->arg)// remove $ from $var
  2273.             fprintf($out"    const %sARG_DECL = '%s';\n"$name$this->arg);
  2274.             $lineno++;
  2275.         else {
  2276.             fprintf($out"    const %sARG_DECL = false;\n"$name);
  2277.             $lineno++;
  2278.         }
  2279.         fprintf($out"    const YYNSTATE = %d;\n"$this->nstate);
  2280.         $lineno++;
  2281.         fprintf($out"    const YYNRULE = %d;\n"$this->nrule);
  2282.         $lineno++;
  2283.         fprintf($out"    const YYERRORSYMBOL = %d;\n"$this->errsym->index);
  2284.         $lineno++;
  2285.         fprintf($out"    const YYERRSYMDT = 'yy%d';\n"$this->errsym->dtnum);
  2286.         $lineno++;
  2287.         if ($this->has_fallback{
  2288.             fwrite($out"    const YYFALLBACK = 1;\n");
  2289.         else {
  2290.             fwrite($out"    const YYFALLBACK = 0;\n");
  2291.         }
  2292.         $lineno++;
  2293.         $this->tplt_xfer($this->name$in$out$lineno);
  2294.  
  2295.         /* Generate the table of fallback tokens.
  2296.         */
  2297.  
  2298.         if ($this->has_fallback{
  2299.             for ($i = 0; $i $this->nterminal$i++{
  2300.                 $p $this->symbols[$i];
  2301.                 if ($p->fallback === 0{
  2302.                     // change next line
  2303.                     fprintf($out"    0,  /* %10s => nothing */\n"$p->name);
  2304.                 else {
  2305.                     // change next line
  2306.                     fprintf($out"  %3d,  /* %10s => %s */\n",
  2307.                         $p->fallback->index$p->name$p->fallback->name);
  2308.                 }
  2309.                 $lineno++;
  2310.             }
  2311.         }
  2312.         $this->tplt_xfer($this->name$in$out$lineno);
  2313.  
  2314.  
  2315.         /* Generate a table containing the symbolic name of every symbol
  2316.             ($yyTokenName)
  2317.         */
  2318.  
  2319.         for ($i = 0; $i $this->nsymbol$i++{
  2320.             fprintf($out,"  %-15s""'" $this->symbols[$i]->name . "',");
  2321.             if (($i 3== 3{
  2322.                 fwrite($out,"\n");
  2323.                 $lineno++;
  2324.             }
  2325.         }
  2326.         if (($i 3!= 0{
  2327.             fwrite($out"\n");
  2328.             $lineno++;
  2329.         }
  2330.         $this->tplt_xfer($this->name$in$out$lineno);
  2331.  
  2332.         /* Generate a table containing a text string that describes every
  2333.         ** rule in the rule set of the grammer.  This information is used
  2334.         ** when tracing REDUCE actions.
  2335.         */
  2336.  
  2337.         for ($i = 0$rp $this->rule$rp$rp $rp->next$i++{
  2338.             if ($rp->index !== $i{
  2339.                 throw new Exception('rp->index != i and should be');
  2340.             }
  2341.             // change next line
  2342.             fprintf($out" /* %3d */ \"%s ::="$i$rp->lhs->name);
  2343.             for ($j = 0; $j $rp->nrhs; $j++{
  2344.                 $sp $rp->rhs[$j];
  2345.                 fwrite($out,' ' $sp->name);
  2346.                 if ($sp->type == lemonSymbol::MULTITERMINAL{
  2347.                     for($k = 1; $k $sp->nsubsym; $k++{
  2348.                         fwrite($out'|' $sp->subsym[$k]->name);
  2349.                     }
  2350.                 }
  2351.             }
  2352.             fwrite($out"\",\n");
  2353.             $lineno++;
  2354.         }
  2355.         $this->tplt_xfer($this->name$in$out$lineno);
  2356.  
  2357.         /* Generate code which executes every time a symbol is popped from
  2358.         ** the stack while processing errors or while destroying the parser. 
  2359.         ** (In other words, generate the %destructor actions)
  2360.         */
  2361.  
  2362.         if ($this->tokendest{
  2363.             for ($i = 0; $i $this->nsymbol$i++{
  2364.                 $sp $this->symbols[$i];
  2365.                 if ($sp === 0 || $sp->type != LemonSymbol::TERMINAL{
  2366.                     continue;
  2367.                 }
  2368.                 fprintf($out"    case %d:\n"$sp->index);
  2369.                 $lineno++;
  2370.             }
  2371.             for ($i = 0; $i $this->nsymbol &&
  2372.                          $this->symbols[$i]->type != LemonSymbol::TERMINAL; $i++);
  2373.             if ($i $this->nsymbol{
  2374.                 $this->emit_destructor_code($out$this->symbols[$i]$lineno);
  2375.                 fprintf($out"      break;\n");
  2376.                 $lineno++;
  2377.             }
  2378.         }
  2379.         if ($this->vardest{
  2380.             $dflt_sp = 0;
  2381.             for ($i = 0; $i $this->nsymbol$i++{
  2382.                 $sp $this->symbols[$i];
  2383.                 if ($sp === 0 || $sp->type == LemonSymbol::TERMINAL ||
  2384.                       $sp->index <= 0 || $sp->destructor != 0{
  2385.                     continue;
  2386.                 }
  2387.                 fprintf($out"    case %d:\n"$sp->index);
  2388.                 $lineno++;
  2389.                 $dflt_sp $sp;
  2390.             }
  2391.             if ($dflt_sp != 0{
  2392.                 $this->emit_destructor_code($out$dflt_sp$lineno);
  2393.                 fwrite($out"      break;\n");
  2394.                 $lineno++;
  2395.             }
  2396.         }
  2397.         for ($i = 0; $i $this->nsymbol$i++{
  2398.             $sp $this->symbols[$i];
  2399.             if ($sp === 0 || $sp->type == LemonSymbol::TERMINAL ||
  2400.                   $sp->destructor === 0{
  2401.                 continue;
  2402.             }
  2403.             fprintf($out"    case %d:\n"$sp->index);
  2404.             $lineno++;
  2405.  
  2406.             /* Combine duplicate destructors into a single case */
  2407.  
  2408.             for ($j $i + 1; $j $this->nsymbol$j++{
  2409.                 $sp2 $this->symbols[$j];
  2410.                 if ($sp2 && $sp2->type != LemonSymbol::TERMINAL && $sp2->destructor
  2411.                       && $sp2->dtnum == $sp->dtnum
  2412.                       && $sp->destructor == $sp2->destructor{
  2413.                     fprintf($out"    case %d:\n"$sp2->index);
  2414.                     $lineno++;
  2415.                     $sp2->destructor = 0;
  2416.                 }
  2417.             }
  2418.         
  2419.             $this->emit_destructor_code($out$this->symbols[$i]$lineno);
  2420.             fprintf($out"      break;\n");
  2421.             $lineno++;
  2422.         }
  2423.         $this->tplt_xfer($this->name$in$out$lineno);
  2424.  
  2425.         /* Generate code which executes whenever the parser stack overflows */
  2426.  
  2427.         $this->tplt_print($out$this->overflow$this->overflowln$lineno);
  2428.         $this->tplt_xfer($this->name$in$out$lineno);
  2429.  
  2430.         /* Generate the table of rule information 
  2431.         **
  2432.         ** Note: This code depends on the fact that rules are number
  2433.         ** sequentually beginning with 0.
  2434.         */
  2435.  
  2436.         for ($rp $this->rule$rp$rp $rp->next{
  2437.             fprintf($out"  array( 'lhs' => %d, 'rhs' => %d ),\n",
  2438.                 $rp->lhs->index$rp->nrhs);
  2439.             $lineno++;
  2440.         }
  2441.         $this->tplt_xfer($this->name$in$out$lineno);
  2442.  
  2443.  
  2444.         /* Generate code which executes during each REDUCE action */
  2445.  
  2446.         for ($rp $this->rule$rp$rp $rp->next{
  2447.             if ($rp->code{
  2448.                 $this->translate_code($rp);
  2449.             }
  2450.         }
  2451.  
  2452.         /* Generate the method map for each REDUCE action */
  2453.  
  2454.         for ($rp $this->rule$rp$rp $rp->next{
  2455.             if ($rp->code === 0{
  2456.                 continue;
  2457.             }
  2458.             fwrite($out'        ' $rp->index . ' => ' $rp->index . ",\n");
  2459.             $lineno++;
  2460.             for ($rp2 $rp->next; $rp2$rp2 $rp2->next{
  2461.                 if ($rp2->code === $rp->code{
  2462.                     fwrite($out'        ' $rp2->index . ' => ' .
  2463.                         $rp->index . ",\n");
  2464.                     $lineno++;
  2465.                     $rp2->code = 0;
  2466.                 }
  2467.             }
  2468.         }
  2469.         $this->tplt_xfer($this->name$in$out$lineno);
  2470.  
  2471.         for ($rp $this->rule$rp$rp $rp->next{
  2472.             if ($rp->code === 0{
  2473.                 continue;
  2474.             }
  2475.             $this->emit_code($out$rp$lineno);
  2476.         }
  2477.         $this->tplt_xfer($this->name$in$out$lineno);
  2478.  
  2479.  
  2480.         /* Generate code which executes if a parse fails */
  2481.  
  2482.         $this->tplt_print($out$this->failure$this->failureln$lineno);
  2483.         $this->tplt_xfer($this->name$in$out$lineno);
  2484.  
  2485.         /* Generate code which executes when a syntax error occurs */
  2486.  
  2487.         $this->tplt_print($out$this->error$this->errorln$lineno);
  2488.         $this->tplt_xfer($this->name$in$out$lineno);
  2489.  
  2490.         /* Generate code which executes when the parser accepts its input */
  2491.  
  2492.         $this->tplt_print($out$this->accept$this->acceptln$lineno);
  2493.         $this->tplt_xfer($this->name$in$out$lineno);
  2494.  
  2495.         /* Append any addition code the user desires */
  2496.  
  2497.         $this->tplt_print($out$this->extracode$this->extracodeln$lineno);
  2498.  
  2499.         fclose($in);
  2500.         fclose($out);
  2501.     }
  2502.  
  2503.     /**
  2504.      * Generate code which executes when the rule "rp" is reduced.  Write
  2505.      * the code to "out".  Make sure lineno stays up-to-date.
  2506.      */
  2507.     function emit_code($outLemonRule $rp&$lineno)
  2508.     {
  2509.         $linecnt = 0;
  2510.         
  2511.         /* Generate code to do the reduce action */
  2512.         if ($rp->code{
  2513.             $this->tplt_linedir($out$rp->line$this->filename);
  2514.             fwrite($out"    function yy_r$rp->index(){" . $rp->code);
  2515.             $linecnt += count(explode("\n"$rp->code)) - 1;
  2516.             $lineno += 3 + $linecnt;
  2517.             fwrite($out"    }\n");
  2518.             $this->tplt_linedir($out$lineno$this->outname);
  2519.         /* End if( rp->code ) */
  2520.     }
  2521.  
  2522.     /**
  2523.      * Append text to a dynamically allocated string.  If zText is 0 then
  2524.      * reset the string to be empty again.  Always return the complete text
  2525.      * of the string (which is overwritten with each call).
  2526.      *
  2527.      * n bytes of zText are stored.  If n==0 then all of zText is stored.
  2528.      *
  2529.      * If n==-1, then the previous character is overwritten.
  2530.      * @param string 
  2531.      * @param int 
  2532.      */
  2533.     function append_str($zText$n)
  2534.     {
  2535.         static $z '';
  2536.         $zInt '';
  2537.         
  2538.         if ($zText === ''{
  2539.             $ret $z;
  2540.             $z '';
  2541.             return $ret;
  2542.         }
  2543.         if ($n <= 0{
  2544.             if ($n < 0{
  2545.                 if (!strlen($z)) {
  2546.                     throw new Exception('z is zero-length');
  2547.                 }
  2548.                 $z substr($z0strlen($z- 1);
  2549.                 if (!$z{
  2550.                     $z '';
  2551.                 }
  2552.             }
  2553.             $n strlen($zText);
  2554.         }
  2555.         $i = 0;
  2556.         $z .= substr($zText0$n);
  2557.         return $z;
  2558.     }
  2559.  
  2560.     /**
  2561.      * zCode is a string that is the action associated with a rule.  Expand
  2562.      * the symbols in this string so that the refer to elements of the parser
  2563.      * stack.
  2564.      */
  2565.     function translate_code(LemonRule $rp)
  2566.     {
  2567.         $lhsused = 0;    /* True if the LHS element has been used */
  2568.         $used = array();   /* True for each RHS element which is used */
  2569.     
  2570.         for($i = 0; $i $rp->nrhs; $i++{
  2571.             $used[$i= 0;
  2572.         }
  2573.         
  2574.         $this->append_str(''0);
  2575.         for ($i = 0; $i strlen($rp->code)$i++{
  2576.             $cp $rp->code[$i];
  2577.             if (preg_match('/[A-Za-z]/'$cp&&
  2578.                  ($i === 0 || (!preg_match('/[A-Za-z0-9_]/'$rp->code[$i - 1])))) {
  2579.                 //*xp = 0;
  2580.                 // previous line is in essence a temporary substr, so
  2581.                 // we will simulate it
  2582.                 $test substr($rp->code$i);
  2583.                 preg_match('/[A-Za-z0-9_]+/'$test$matches);
  2584.                 $tempcp $matches[0];
  2585.                 $j strlen($tempcp$i;
  2586.                 if ($rp->lhsalias && $tempcp == $rp->lhsalias{
  2587.                     $this->append_str("\$this->_retvalue"0);
  2588.                     $cp $rp->code[$j];
  2589.                     $i $j;
  2590.                     $lhsused = 1;
  2591.                 else {
  2592.                     for ($ii = 0; $ii $rp->nrhs; $ii++{
  2593.                         if ($rp->rhsalias[$ii&& $tempcp == $rp->rhsalias[$ii]{
  2594.                             if ($ii !== 0 && $rp->code[$ii - 1== '@'{
  2595.                                 /* If the argument is of the form @X then substitute
  2596.                                 ** the token number of X, not the value of X */
  2597.                                 $this->append_str("\$this->yystack[\$this->yyidx + " .
  2598.                                     ($ii $rp->nrhs + 1"]->major"-1);
  2599.                             else {
  2600.                                 $sp $rp->rhs[$ii];
  2601.                                 if ($sp->type == LemonSymbol::MULTITERMINAL{
  2602.                                     $dtnum $sp->subsym[0]->dtnum;
  2603.                                 else {
  2604.                                     $dtnum $sp->dtnum;
  2605.                                 }
  2606.                                 $this->append_str("\$this->yystack[\$this->yyidx + " .
  2607.                                     ($ii $rp->nrhs + 1"]->minor"0);
  2608.                             }
  2609.                             $cp $rp->code[$j];
  2610.                             $i $j;
  2611.                             $used[$ii= 1;
  2612.                             break;
  2613.                         }
  2614.                     }
  2615.                 }
  2616.             }
  2617.             $this->append_str($cp1);
  2618.         /* End loop */
  2619.         
  2620.         /* Check to make sure the LHS has been used */
  2621.         if ($rp->lhsalias && !$lhsused{
  2622.             Lemon::ErrorMsg($this->filename$rp->ruleline,
  2623.                 "Label \"%s\" for \"%s(%s)\" is never used.",
  2624.                 $rp->lhsalias$rp->lhs->name$rp->lhsalias);
  2625.                 $this->errorcnt++;
  2626.         }
  2627.         
  2628.         /* Generate destructor code for RHS symbols which are not used in the
  2629.         ** reduce code */
  2630.         for($i = 0; $i $rp->nrhs; $i++{
  2631.             if ($rp->rhsalias[$i&& !isset($used[$i])) {
  2632.                 Lemon::ErrorMsg($this->filename$rp->ruleline,
  2633.                     "Label %s for \"%s(%s)\" is never used.",
  2634.                     $rp->rhsalias[$i]$rp->rhs[$i]->name$rp->rhsalias[$i]);
  2635.                 $this->errorcnt++;
  2636.             elseif ($rp->rhsalias[$i== 0{
  2637.                 if ($rp->rhs[$i]->type == LemonSymbol::TERMINAL{
  2638.                     $hasdestructor $this->tokendest != 0;
  2639.                 }else{
  2640.                     $hasdestructor $this->vardest !== 0 || $rp->rhs[$i]->destructor !== 0;
  2641.                 }
  2642.                 if ($hasdestructor{
  2643.                     $this->append_str("  \$this->yy_destructor(" .
  2644.                         ($rp->rhs[$i]->index", \$this->yystack[\$this->yyidx + " .
  2645.                         ($i $rp->nrhs + 1"]->minor);\n"0);
  2646.                 else {
  2647.                     /* No destructor defined for this term */
  2648.                 }
  2649.             }
  2650.         }
  2651.         $cp $this->append_str(''0);
  2652.         $rp->code = $cp;
  2653.     }
  2654.  
  2655.     /**
  2656.      * The following routine emits code for the destructor for the
  2657.      * symbol sp
  2658.      */
  2659.     function emit_destructor_code($outLemonSymbol $sp&$lineno)
  2660. //    FILE *out;
  2661. //    struct symbol *sp;
  2662. //    struct lemon *lemp;
  2663. //    int *lineno;
  2664.     {
  2665.         $cp = 0;
  2666.         
  2667.         $linecnt = 0;
  2668.         if ($sp->type == LemonSymbol::TERMINAL{
  2669.             $cp $this->tokendest;
  2670.             if ($cp === 0{
  2671.                 return;
  2672.             }
  2673.             $this->tplt_linedir($out$this->tokendestln$this->filename);
  2674.             fwrite($out"{");
  2675.         elseif ($sp->destructor{
  2676.             $cp $sp->destructor;
  2677.             $this->tplt_linedir($out$sp->destructorln$this->filename);
  2678.             fwrite($out"{");
  2679.         elseif ($this->vardest{
  2680.             $cp $this->vardest;
  2681.             if ($cp === 0{
  2682.                 return;
  2683.             }
  2684.             $this->tplt_linedir($out$this->vardestln$this->filename);
  2685.             fwrite($out"{");
  2686.         else {
  2687.             throw new Exception('emit_destructor')/* Cannot happen */
  2688.         }
  2689.         for ($i = 0; $i strlen($cp)$i++{
  2690.             if ($cp[$i]=='$' && $cp[$i + 1]=='$' {
  2691.                 fprintf($out"(yypminor->yy%d)"$sp->dtnum);
  2692.                 $i++;
  2693.                 continue;
  2694.             }
  2695.             if ($cp[$i== "\n"{
  2696.                 $linecnt++;
  2697.             }
  2698.             fwrite($out$cp[$i]);
  2699.         }
  2700.         $lineno += 3 + $linecnt;
  2701.         fwrite($out"}\n");
  2702.         $this->tplt_linedir($out$lineno$this->outname);
  2703.     }
  2704.  
  2705.     /**
  2706.      * Compare to axset structures for sorting purposes
  2707.      */
  2708.     static function axset_compare($a$b)
  2709.     {
  2710.         return $b['nAction'$a['nAction'];
  2711.     }
  2712. }
  2713.  
  2714. class Lemon
  2715. {
  2716.     const MAXRHS = 1000;
  2717.     const OPT_FLAG = 1OPT_INT = 2OPT_DBL = 3OPT_STR = 4,
  2718.           OPT_FFLAG = 5OPT_FINT = 6OPT_FDBL = 7OPT_FSTR = 8;
  2719.     public $azDefine = array();
  2720.     private static $options = array(
  2721.         'b' => array(
  2722.             'type' => self::OPT_FLAG,
  2723.             'arg' => 'basisflag',
  2724.             'message' => 'Print only the basis in report.'
  2725.         ),
  2726.         'c' => array(
  2727.             'type' => self::OPT_FLAG,
  2728.             'arg' => 'compress',
  2729.             'message' => 'Don\'t compress the action table.'
  2730.         ),
  2731.         'D' => array(
  2732.             'type' => self::OPT_FSTR,
  2733.             'arg' => 'handle_D_option',
  2734.             'message' => 'Define an %ifdef macro.'
  2735.         ),
  2736.         'g' => array(
  2737.             'type' => self::OPT_FLAG,
  2738.             'arg' => 'rpflag',
  2739.             'message' => 'Print grammar without actions.'
  2740.         ),
  2741.         'm' => array(
  2742.             'type' => self::OPT_FLAG,
  2743.             'arg' => 'mhflag',
  2744.             'message' => 'Output a makeheaders compatible file'
  2745.         ),
  2746.         'q' => array(
  2747.             'type' => self::OPT_FLAG,
  2748.             'arg' => 'quiet',
  2749.             'message' => '(Quiet) Don\'t print the report file.'
  2750.         ),
  2751.         's' => array(
  2752.             'type' => self::OPT_FLAG,
  2753.             'arg' => 'statistics',
  2754.             'message' => 'Print parser stats to standard output.'
  2755.         ),
  2756.         'x' => array(
  2757.             'type' => self::OPT_FLAG,
  2758.             'arg' => 'version',
  2759.             'message' => 'Print the version number.'
  2760.         )
  2761.     );
  2762.  
  2763.     private $basisflag = 0;
  2764.     private $compress = 0;
  2765.     private $rpflag = 0;
  2766.     private $mhflag = 0;
  2767.     private $quiet = 0;
  2768.     private $statistics = 0;
  2769.     private $version = 0;
  2770.     private $size;
  2771.     /**
  2772.      * Process a flag command line argument.
  2773.      * @param int 
  2774.      * @param array 
  2775.      * @return int 
  2776.      */
  2777.     function handleflags($i$argv)
  2778.     {
  2779.         if (!isset($argv[1]|| !isset(self::$options[$argv[$i][1]])) {
  2780.             throw new Exception('Command line syntax error: undefined option "' .  $argv[$i'"');
  2781.         }
  2782.         $v = self::$options[$argv[$i][1]] == '-';
  2783.         if (self::$options[$argv[$i][1]]['type'== self::OPT_FLAG{
  2784.             $this->{self::$options[$argv[$i][1]]['arg']= (int) $v;
  2785.         elseif (self::$options[$argv[$i][1]]['type'== self::OPT_FFLAG{
  2786.             $this->{self::$options[$argv[$i][1]]['arg']}($v);
  2787.         elseif (self::$options[$argv[$i][1]]['type'== self::OPT_FSTR{
  2788.             $this->{self::$options[$argv[$i][1]]['arg']}(substr($v2));
  2789.         else {
  2790.             throw new Exception('Command line syntax error: missing argument on switch: "' $argv[$i'"');
  2791.         }
  2792.         return 0;
  2793.     }
  2794.  
  2795.     /**
  2796.      * Process a command line switch which has an argument.
  2797.      * @param int 
  2798.      * @param array 
  2799.      * @param array 
  2800.      * @return int 
  2801.      */
  2802.     function handleswitch($i$argv)
  2803.     {
  2804.         $lv = 0;
  2805.         $dv = 0.0;
  2806.         $sv $end $cp '';
  2807.         $j// int
  2808.         $errcnt = 0;
  2809.         $cp strstr($argv[$i],'=');
  2810.         if (!$cp{
  2811.             throw new Exception('INTERNAL ERROR: handleswitch passed bad argument, no "=" in arg');
  2812.         }
  2813.         $argv[$isubstr($argv[$i]0strlen($argv[$i]strlen($cp));
  2814.         if (!isset(self::$options[$argv[$i]])) {
  2815.             throw new Exception('Command line syntax error: undefined option "' .  $argv[$i.
  2816.                 $cp '"');
  2817.         }
  2818.         $cp substr($cp1);
  2819.         switch (self::$options[$argv[$i]]['type']{
  2820.             case self::OPT_FLAG:
  2821.             case self::OPT_FFLAG:
  2822.                 throw new Exception('Command line syntax error: option requires an argument "' .
  2823.                     $argv[$i'=' $cp '"');
  2824.             case self::OPT_DBL:
  2825.             case self::OPT_FDBL:
  2826.                 $dv = (double) $cp;
  2827.                 break;
  2828.             case self::OPT_INT:
  2829.             case self::OPT_FINT:
  2830.                 $lv = (int) $cp;
  2831.                 break;
  2832.             case self::OPT_STR:
  2833.             case self::OPT_FSTR:
  2834.                 $sv $cp;
  2835.                 break;
  2836.         }
  2837.         switch(self::$options[$argv[$i]]['type']{
  2838.             case self::OPT_FLAG:
  2839.             case self::OPT_FFLAG:
  2840.                 break;
  2841.             case self::OPT_DBL:
  2842.                 $this->${self::$options[$argv[$i]]['arg']$dv;
  2843.                 break;
  2844.             case self::OPT_FDBL:
  2845.                 $this->${self::$options[$argv[$i]]['arg']}($dv);
  2846.                 break;
  2847.             case self::OPT_INT:
  2848.                 $this->${self::$options[$argv[$i]]['arg']$lv;
  2849.                 break;
  2850.             case self::OPT_FINT:
  2851.                 $this->${self::$options[$argv[$i]]['arg']}($lv);
  2852.                 break;
  2853.             case self::OPT_STR:
  2854.                 $this->${self::$options[$argv[$i]]['arg']$sv;
  2855.                 break;
  2856.             case self::OPT_FSTR:
  2857.                 $this->${self::$options[$argv[$i]]['arg']}($sv);
  2858.                 break;
  2859.         }
  2860.         return 0;
  2861.     }
  2862.  
  2863.     /**
  2864.      * @param array arguments
  2865.      * @param array valid options
  2866.      * @return int 
  2867.      */
  2868.     function OptInit($a)
  2869.     {
  2870.         $errcnt = 0;
  2871.         $argv $a;
  2872.         try {
  2873.             if (is_array($argv&& count($argv&& self::$options{
  2874.                 for($i = 1; $i < count($argv)$i++{
  2875.                     if ($argv[$i][0== '+' || $argv[$i][0== '-'{
  2876.                         $errcnt += $this->handleflags($i$argv);
  2877.                     elseif (strstr($argv[$i],'=')) {
  2878.                         $errcnt += $this->handleswitch(i$argv);
  2879.                     }
  2880.                 }
  2881.             }
  2882.         catch (Exception $e{
  2883.             OptPrint();
  2884.             echo $e;
  2885.             exit(1);
  2886.         }
  2887.         return 0;
  2888.     }
  2889.  
  2890.     /**
  2891.      * Return the index of the N-th non-switch argument.  Return -1
  2892.      * if N is out of range.
  2893.      * @param int 
  2894.      * @return int 
  2895.      */
  2896.     private function argindex($n$a)
  2897.     {
  2898.         $dashdash = 0;
  2899.         if (!is_array($a|| !count($a)) {
  2900.             return -1;
  2901.         }
  2902.         for ($i=1; $i count($a)$i++{
  2903.             if ($dashdash || !($a[$i][0== '-' || $a[$i][0== '+' ||
  2904.                   strchr($a[$i]'='))) {
  2905.                 if ($n == 0{
  2906.                     return $i;
  2907.                 }
  2908.                 $n--;
  2909.             }
  2910.             if ($_SERVER['argv'][$i== '--'{
  2911.                 $dashdash = 1;
  2912.             }
  2913.         }
  2914.         return -1;
  2915.     }
  2916.  
  2917.     /**
  2918.      * Return the value of the non-option argument as indexed by $i
  2919.      *
  2920.      * @param int 
  2921.      * @param array the value of $argv
  2922.      * @return 0|string
  2923.      */
  2924.     private function OptArg($i$a)
  2925.     {
  2926.         if (-1 == ($ind $this->argindex($i$a))) {
  2927.             return 0;
  2928.         }
  2929.         return $a[$ind];
  2930.     }
  2931.  
  2932.     /**
  2933.      * @return int number of arguments
  2934.      */
  2935.     function OptNArgs($a)
  2936.     {
  2937.         $cnt $dashdash = 0;
  2938.         if (is_array($a&& count($a)) {
  2939.             for($i = 1; $i count($a)$i++{
  2940.                 if ($dashdash || !($a[$i][0== '-' || $a[$i][0== '+' ||
  2941.                       strchr($a[$i]'='))) {
  2942.                     $cnt++;
  2943.                 }
  2944.                 if ($a[$i== "--"{
  2945.                     $dashdash = 1;
  2946.                 }
  2947.             }
  2948.         }
  2949.         return $cnt;
  2950.     }
  2951.  
  2952.     /**
  2953.      * Print out command-line options
  2954.      */
  2955.     function OptPrint()
  2956.     {
  2957.         $max = 0;
  2958.         foreach (self::$options as $label => $info{
  2959.             $len = strlen($label+ 1;
  2960.             switch ($info['type']{
  2961.                 case self::OPT_FLAG:
  2962.                 case self::OPT_FFLAG:
  2963.                     break;
  2964.                 case self::OPT_INT:
  2965.                 case self::OPT_FINT:
  2966.                     $len += 9;       /* length of "<integer>" */
  2967.                     break;
  2968.                 case self::OPT_DBL:
  2969.                 case self::OPT_FDBL:
  2970.                     $len += 6;       /* length of "<real>" */
  2971.                     break;
  2972.                 case self::OPT_STR:
  2973.                 case self::OPT_FSTR:
  2974.                     $len += 8;       /* length of "<string>" */
  2975.                     break;
  2976.             }
  2977.             if ($len $max{
  2978.                 $max $len;
  2979.             }
  2980.         }
  2981.         foreach (self::$options as $label => $info{
  2982.             switch ($info['type']{
  2983.                 case self::OPT_FLAG:
  2984.                 case self::OPT_FFLAG:
  2985.                     printf("  -%-*s  %s\n"$max$label$info['message']);
  2986.                     break;
  2987.                 case self::OPT_INT:
  2988.                 case self::OPT_FINT:
  2989.                     printf("  %s=<integer>%*s  %s\n"$label$max strlen($label- 9,
  2990.                         $info['message']);
  2991.                     break;
  2992.                 case self::OPT_DBL:
  2993.                 case self::OPT_FDBL:
  2994.                     printf("  %s=<real>%*s  %s\n"$label$max strlen($label- 6,
  2995.                         $info['message']);
  2996.                     break;
  2997.                 case self::OPT_STR:
  2998.                 case self::OPT_FSTR:
  2999.                     printf("  %s=<string>%*s  %s\n"$label$max strlen($label- 8,
  3000.                         $info['message']);
  3001.                     break;
  3002.             }
  3003.         }
  3004.     }
  3005.  
  3006.     /**
  3007.     * This routine is called with the argument to each -D command-line option.
  3008.     * Add the macro defined to the azDefine array.
  3009.     * @param string 
  3010.     */
  3011.     private function handle_D_option($z)
  3012.     {
  3013.         if ($a strstr($z'=')) {
  3014.             $z substr($a1)// strip first =
  3015.         }
  3016.         $this->azDefine[$z;
  3017.     }
  3018.  
  3019.     /**************** From the file "main.c" ************************************/
  3020. /*
  3021. ** Main program file for the LEMON parser generator.
  3022. */
  3023.  
  3024.  
  3025.     /* The main program.  Parse the command line and do it... */
  3026.     function main()
  3027.     {
  3028.         $lem = new LemonData;
  3029.  
  3030.         $this->OptInit($_SERVER['argv']);
  3031.         if ($this->version{
  3032.             echo "Lemon version 1.0/PHP port version 1.0\n";
  3033.             exit(0)
  3034.         }
  3035.         if ($this->OptNArgs($_SERVER['argv']!= 1{
  3036.             echo "Exactly one filename argument is required.\n";
  3037.             exit(1);
  3038.         }
  3039.         $lem->errorcnt = 0;
  3040.  
  3041.         /* Initialize the machine */
  3042.         $lem->argv0 = $_SERVER['argv'][0];
  3043.         $lem->filename = $this->OptArg(0$_SERVER['argv']);
  3044.         $a pathinfo($lem->filename);
  3045.         if (isset($a['extension'])) {
  3046.             $ext '.' $a['extension'];
  3047.             $lem->filenosuffix = substr($lem->filename0strlen($lem->filenamestrlen($ext));
  3048.         else {
  3049.             $lem->filenosuffix = $lem->filename;
  3050.         }
  3051.         $lem->basisflag = $this->basisflag;
  3052.         $lem->has_fallback = 0;
  3053.         $lem->nconflict = 0;
  3054.         $lem->name = $lem->include_code = $lem->include_classcode = $lem->arg =
  3055.             $lem->tokentype = $lem->start = 0;
  3056.         $lem->vartype = 0;
  3057.         $lem->stacksize = 0;
  3058.         $lem->error = $lem->overflow = $lem->failure = $lem->accept = $lem->tokendest =
  3059.           $lem->tokenprefix = $lem->outname = $lem->extracode = 0;
  3060.         $lem->vardest = 0;
  3061.         $lem->tablesize = 0;
  3062.         LemonSymbol::Symbol_new("$");
  3063.         $lem->errsym = LemonSymbol::Symbol_new("error");
  3064.  
  3065.         /* Parse the input file */
  3066.         $parser = new LemonParser($this);
  3067.         $parser->Parse($lem);
  3068.         if ($lem->errorcnt{
  3069.             exit($lem->errorcnt);
  3070.         }
  3071.         if ($lem->rule === 0{
  3072.             printf("Empty grammar.\n");
  3073.             exit(1);
  3074.         }
  3075.  
  3076.         /* Count and index the symbols of the grammar */
  3077.         $lem->nsymbol = LemonSymbol::Symbol_count();
  3078.         LemonSymbol::Symbol_new("{default}");
  3079.         $lem->symbols = LemonSymbol::Symbol_arrayof();
  3080.         for ($i = 0; $i <= $lem->nsymbol; $i++{
  3081.             $lem->symbols[$i]->index = $i;
  3082.         }
  3083.         usort($lem->symbolsarray('LemonSymbol''sortSymbols'));
  3084.         for ($i = 0; $i <= $lem->nsymbol; $i++{
  3085.             $lem->symbols[$i]->index = $i;
  3086.         }
  3087.         // find the first lower-case symbol
  3088.         for($i = 1; ord($lem->symbols[$i]->name[0]ord ('Z')$i++);
  3089.         $lem->nterminal = $i;
  3090.  
  3091.         /* Generate a reprint of the grammar, if requested on the command line */
  3092.         if ($this->rpflag{
  3093.             $this->Reprint();
  3094.         else {
  3095.             /* Initialize the size for all follow and first sets */
  3096.             $this->SetSize($lem->nterminal);
  3097.  
  3098.             /* Find the precedence for every production rule (that has one) */
  3099.             $lem->FindRulePrecedences();
  3100.  
  3101.             /* Compute the lambda-nonterminals and the first-sets for every
  3102.             ** nonterminal */
  3103.             $lem->FindFirstSets();
  3104.  
  3105.             /* Compute all LR(0) states.  Also record follow-set propagation
  3106.             ** links so that the follow-set can be computed later */
  3107.             $lem->nstate = 0;
  3108.             $lem->FindStates();
  3109.             $lem->sorted = LemonState::State_arrayof();
  3110.  
  3111.             /* Tie up loose ends on the propagation links */
  3112.             $lem->FindLinks();
  3113.  
  3114.             /* Compute the follow set of every reducible configuration */
  3115.             $lem->FindFollowSets();
  3116.  
  3117.             /* Compute the action tables */
  3118.             $lem->FindActions();
  3119.  
  3120.             /* Compress the action tables */
  3121.             if ($this->compress===0{
  3122.                 $lem->CompressTables();
  3123.             }
  3124.  
  3125.             /* Reorder and renumber the states so that states with fewer choices
  3126.             ** occur at the end. */
  3127.             $lem->ResortStates();
  3128.  
  3129.             /* Generate a report of the parser generated.  (the "y.output" file) */
  3130.             if (!$this->quiet{
  3131.                 $lem->ReportOutput();
  3132.             }
  3133.  
  3134.             /* Generate the source code for the parser */
  3135.             $lem->ReportTable($this->mhflag);
  3136.  
  3137.     /* Produce a header file for use by the scanner.  (This step is
  3138.     ** omitted if the "-m" option is used because makeheaders will
  3139.     ** generate the file for us.) */
  3140. //            if (!$this->mhflag) {
  3141. //                $this->ReportHeader();
  3142. //            }
  3143.         }
  3144.         if ($this->statistics{
  3145.             printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n",
  3146.                 $lem->nterminal$lem->nsymbol - $lem->nterminal$lem->nrule);
  3147.             printf("                   %d states, %d parser table entries, %d conflicts\n",
  3148.                 $lem->nstate$lem->tablesize$lem->nconflict);
  3149.         }
  3150.         if ($lem->nconflict{
  3151.             printf("%d parsing conflicts.\n"$lem->nconflict);
  3152.         }
  3153.         exit($lem->errorcnt + $lem->nconflict);
  3154.         return ($lem->errorcnt + $lem->nconflict);
  3155.     }
  3156.  
  3157.     function SetSize($n)
  3158.     {
  3159.         $this->size = $n + 1;
  3160.     }
  3161.  
  3162.     /**
  3163.      * Merge in a merge sort for a linked list
  3164.      * Inputs:
  3165.      *  - a:       A sorted, null-terminated linked list.  (May be null).
  3166.      *  - b:       A sorted, null-terminated linked list.  (May be null).
  3167.      *  - cmp:     A pointer to the comparison function.
  3168.      *  - offset:  Offset in the structure to the "next" field.
  3169.      *
  3170.      * Return Value:
  3171.      *   A pointer to the head of a sorted list containing the elements
  3172.      *   of both a and b.
  3173.      *
  3174.      * Side effects:
  3175.      *   The "next" pointers for elements in the lists a and b are
  3176.      *   changed.
  3177.      */
  3178.     static function merge($a$b$cmp$offset)
  3179.     {
  3180.         if($a === 0{
  3181.             $head $b;
  3182.         elseif ($b === 0{
  3183.             $head $a;
  3184.         else {
  3185.             if (call_user_func($cmp$a$b< 0{
  3186.                 $ptr $a;
  3187.                 $a $a->$offset;
  3188.             else {
  3189.                 $ptr $b;
  3190.                 $b $b->$offset;
  3191.             }
  3192.             $head $ptr;
  3193.             while ($a && $b{
  3194.                 if (call_user_func($cmp$a$b< 0{
  3195.                     $ptr->$offset $a;
  3196.                     $ptr $a;
  3197.                     $a $a->$offset;
  3198.                 else {
  3199.                     $ptr->$offset $b;
  3200.                     $ptr $b;
  3201.                     $b $b->$offset;
  3202.                 }
  3203.             }
  3204.             if ($a !== 0{
  3205.                 $ptr->$offset $a;
  3206.             else {
  3207.                 $ptr->$offset $b;
  3208.             }
  3209.         }
  3210.         return $head;
  3211.     }
  3212.     
  3213.     /*
  3214.     ** Inputs:
  3215.     **   list:      Pointer to a singly-linked list of structures.
  3216.     **   next:      Pointer to pointer to the second element of the list.
  3217.     **   cmp:       A comparison function.
  3218.     **
  3219.     ** Return Value:
  3220.     **   A pointer to the head of a sorted list containing the elements
  3221.     **   orginally in list.
  3222.     **
  3223.     ** Side effects:
  3224.     **   The "next" pointers for elements in list are changed.
  3225.     */
  3226.     #define LISTSIZE 30
  3227.     static function msort($list$next$cmp)
  3228.     {
  3229.         if ($list === 0{
  3230.             return $list;
  3231.         }
  3232.         if ($list->$next === 0{
  3233.             return $list;
  3234.         }
  3235.         $set array_fill(0300);
  3236.         while ($list{
  3237.             $ep $list;
  3238.             $list $list->$next;
  3239.             $ep->$next = 0;
  3240.             for ($i = 0; $i < 29 && $set[$i!== 0; $i++{
  3241.                 $ep = self::merge($ep$set[$i]$cmp$next);
  3242.                 $set[$i= 0;
  3243.             }
  3244.             $set[$i$ep;
  3245.         }
  3246.         $ep = 0;
  3247.         for ($i = 0; $i < 30; $i++{
  3248.             if ($set[$i!== 0{
  3249.                 $ep = self::merge($ep$set[$i]$cmp$next);
  3250.             }
  3251.         }
  3252.         return $ep;
  3253.     }
  3254.  
  3255.     /* Find a good place to break "msg" so that its length is at least "min"
  3256.     ** but no more than "max".  Make the point as close to max as possible.
  3257.     */
  3258.     static function findbreak($msg$min$max)
  3259.     {
  3260.         if ($min >= strlen($msg)) {
  3261.             return strlen($msg);
  3262.         }
  3263.         for ($i $spot $min$i <= $max && $i strlen($msg)$i++{
  3264.             $c $msg[$i];
  3265.             if ($c == '-' && $i $max - 1{
  3266.                 $spot $i + 1;
  3267.             }
  3268.             if ($c == ' '{
  3269.                 $spot $i;
  3270.             }
  3271.         }
  3272.         return $spot;
  3273.     }
  3274.  
  3275.     static function ErrorMsg($filename$lineno$format)
  3276.     {
  3277.         /* Prepare a prefix to be prepended to every output line */
  3278.         if ($lineno > 0{
  3279.             $prefix sprintf("%20s:%d: "$filename$lineno);
  3280.         else {
  3281.             $prefix sprintf("%20s: "$filename);
  3282.         }
  3283.         $prefixsize strlen($prefix);
  3284.         $availablewidth = 79 - $prefixsize;
  3285.         
  3286.         /* Generate the error message */
  3287.         $ap func_get_args();
  3288.         array_shift($ap)// $filename
  3289.         array_shift($ap)// $lineno
  3290.         array_shift($ap)// $format
  3291.         $errmsg vsprintf($format$ap);
  3292.         $linewidth strlen($errmsg);
  3293.         /* Remove trailing "\n"s from the error message. */
  3294.         while ($linewidth > 0 && in_array($errmsg[$linewidth-1]array("\n""\r")true)) {
  3295.             --$linewidth;
  3296.             $errmsg substr($errmsg0strlen($errmsg- 1);
  3297.         }
  3298.         
  3299.         /* Print the error message */
  3300.         $base = 0;
  3301.         $errmsg str_replace(array("\r""\n""\t")array(' '' '' ')$errmsg);
  3302.         while (strlen($errmsg)) {
  3303.             $end $restart = self::findbreak($errmsg0$availablewidth);
  3304.             if (strlen($errmsg<= 79 && $end strlen($errmsg&& $end <= 79{
  3305.                 $end $restart strlen($errmsg);
  3306.             }
  3307.             while (isset($errmsg[$restart]&& $errmsg[$restart== ' '{
  3308.                 $restart++;
  3309.             }
  3310.             printf("%s%.${end}s\n"$prefix$errmsg);
  3311.             $errmsg substr($errmsg$restart);
  3312.         }
  3313.     }
  3314.  
  3315.     /**
  3316.      * Duplicate the input file without comments and without actions
  3317.      * on rules
  3318.      */
  3319.     function Reprint()
  3320.     {
  3321.         printf("// Reprint of input file \"%s\".\n// Symbols:\n"$this->filename);
  3322.         $maxlen = 10;
  3323.         for ($i = 0; $i $this->nsymbol; $i++{
  3324.             $sp $this->symbols[$i];
  3325.             $len strlen($sp->name);
  3326.             if ($len $maxlen {
  3327.                 $maxlen $len;
  3328.             }
  3329.         }
  3330.         $ncolumns = 76 / ($maxlen + 5);
  3331.         if ($ncolumns < 1{
  3332.             $ncolumns = 1;
  3333.         }
  3334.         $skip ($this->nsymbol + $ncolumns - 1$ncolumns;
  3335.         for ($i = 0; $i $skip$i++{
  3336.             print "//";
  3337.             for ($j $i$j $this->nsymbol; $j += $skip{
  3338.                 $sp $this->symbols[$j];
  3339.                 //assert( sp->index==j );
  3340.                 printf(" %3d %-${maxlen}.${maxlen}s"$j$sp->name);
  3341.             }
  3342.             print "\n";
  3343.         }
  3344.         for ($rp $this->rule; $rp$rp $rp->next{
  3345.             printf("%s"$rp->lhs->name);
  3346. /*          if ($rp->lhsalias) {
  3347.                 printf("(%s)", $rp->lhsalias);
  3348.             }*/
  3349.             print " ::=";
  3350.             for ($i = 0; $i $rp->nrhs; $i++{
  3351.                 $sp $rp->rhs[$i];
  3352.                 printf(" %s"$sp->name);
  3353.                 if ($sp->type == LemonSymbol::MULTITERMINAL{
  3354.                     for ($j = 1; $j $sp->nsubsym; $j++{
  3355.                         printf("|%s"$sp->subsym[$j]->name);
  3356.                     }
  3357.                 }
  3358. /*              if ($rp->rhsalias[$i]) {
  3359.                     printf("(%s)", $rp->rhsalias[$i]);
  3360.                 }*/
  3361.             }
  3362.             print ".";
  3363.             if ($rp->precsym{
  3364.                 printf(" [%s]"$rp->precsym->name);
  3365.             }
  3366. /*          if ($rp->code) {
  3367.                 print "\n    " . $rp->code);
  3368.             }*/
  3369.             print "\n";
  3370.         }
  3371.     }
  3372. }
  3373.  
  3374. class LemonParser
  3375. {
  3376.     const INITIALIZE = 1;
  3377.     const WAITING_FOR_DECL_OR_RULE = 2;
  3378.     const WAITING_FOR_DECL_KEYWORD = 3;
  3379.     const WAITING_FOR_DECL_ARG = 4;
  3380.     const WAITING_FOR_PRECEDENCE_SYMBOL = 5;
  3381.     const WAITING_FOR_ARROW = 6;
  3382.     const IN_RHS = 7;
  3383.     const LHS_ALIAS_1 = 8;
  3384.     const LHS_ALIAS_2 = 9;
  3385.     const LHS_ALIAS_3 = 10;
  3386.     const RHS_ALIAS_1 = 11;
  3387.     const RHS_ALIAS_2 = 12;
  3388.     const PRECEDENCE_MARK_1 = 13;
  3389.     const PRECEDENCE_MARK_2 = 14;
  3390.     const RESYNC_AFTER_RULE_ERROR = 15;
  3391.     const RESYNC_AFTER_DECL_ERROR = 16;
  3392.     const WAITING_FOR_DESTRUCTOR_SYMBOL = 17;
  3393.     const WAITING_FOR_DATATYPE_SYMBOL = 18;
  3394.     const WAITING_FOR_FALLBACK_ID = 19;
  3395.  
  3396.     public $filename;       /* Name of the input file */
  3397.     public $tokenlineno;      /* Linenumber at which current token starts */
  3398.     public $errorcnt;         /* Number of errors so far */
  3399.     public $tokenstart;     /* Text of current token */
  3400.     /**
  3401.      * @var LemonData 
  3402.      */
  3403.     public $gp;     /* Global state vector */
  3404.   /* enum e_state {
  3405.     INITIALIZE,
  3406.     WAITING_FOR_DECL_OR_RULE,
  3407.     WAITING_FOR_DECL_KEYWORD,
  3408.     WAITING_FOR_DECL_ARG,
  3409.     WAITING_FOR_PRECEDENCE_SYMBOL,
  3410.     WAITING_FOR_ARROW,
  3411.     IN_RHS,
  3412.     LHS_ALIAS_1,
  3413.     LHS_ALIAS_2,
  3414.     LHS_ALIAS_3,
  3415.     RHS_ALIAS_1,
  3416.     RHS_ALIAS_2,
  3417.     PRECEDENCE_MARK_1,
  3418.     PRECEDENCE_MARK_2,
  3419.     RESYNC_AFTER_RULE_ERROR,
  3420.     RESYNC_AFTER_DECL_ERROR,
  3421.     WAITING_FOR_DESTRUCTOR_SYMBOL,
  3422.     WAITING_FOR_DATATYPE_SYMBOL,
  3423.     WAITING_FOR_FALLBACK_ID
  3424.   } */
  3425.     public $state;                   /* The state of the parser */
  3426.     /**
  3427.      * @var LemonSymbol 
  3428.      */
  3429.     public $fallback;   /* The fallback token */
  3430.     /**
  3431.      * @var LemonSymbol 
  3432.      */
  3433.     public $lhs;        /* Left-hand side of current rule */
  3434.     public $lhsalias;            /* Alias for the LHS */
  3435.     public $nrhs;                  /* Number of right-hand side symbols seen */
  3436.     /**
  3437.      * @var array array of {@link LemonSymbol} objects
  3438.      */
  3439.     public $rhs = array();  /* RHS symbols */
  3440.     public $alias = array();       /* Aliases for each RHS symbol name (or NULL) */
  3441.     /**
  3442.      * @var LemonRule 
  3443.      */
  3444.     public $prevrule;     /* Previous rule parsed */
  3445.     public $declkeyword;         /* Keyword of a declaration */
  3446.     /**
  3447.      * @var array array of strings
  3448.      */
  3449.     public $declargslot = array();        /* Where the declaration argument should be put */
  3450.     public $decllnslot;           /* Where the declaration linenumber is put */
  3451.     /*enum e_assoc*/
  3452.     public $declassoc;    /* Assign this association to decl arguments */
  3453.     public $preccounter;           /* Assign this precedence to decl arguments */
  3454.     /**
  3455.      * @var LemonRule 
  3456.      */
  3457.     public $firstrule;    /* Pointer to first rule in the grammar */
  3458.     /**
  3459.      * @var LemonRule 
  3460.      */
  3461.     public $lastrule;     /* Pointer to the most recently parsed rule */
  3462.  
  3463.     /**
  3464.      * @var Lemon 
  3465.      */
  3466.     private $lemon;
  3467.  
  3468.     function __construct($lem)
  3469.     {
  3470.         $this->lemon $lem;
  3471.     }
  3472.     /**
  3473.      * Run the proprocessor over the input file text.  The Lemon variable
  3474.      * $azDefine contains the names of all defined
  3475.      * macros.  This routine looks for "%ifdef" and "%ifndef" and "%endif" and
  3476.      * comments them out.  Text in between is also commented out as appropriate.
  3477.      */
  3478.     private function preprocess_input(&$z)
  3479.     {
  3480.         $lineno $exclude = 0;
  3481.         for ($i=0; $i strlen($z)$i++{
  3482.             if ($z[$i== "\n"{
  3483.                 $lineno++;
  3484.             }
  3485.             if ($z[$i!= '%' || ($i > 0 && $z[$i-1!= "\n")) {
  3486.                 continue;
  3487.             }
  3488.             if (substr($z$i6=== "%endif" && trim($z[$i+6]=== ''{
  3489.                 if ($exclude{
  3490.                     $exclude--;
  3491.                     if ($exclude === 0{
  3492.                         for ($j $start$j $i$j++{
  3493.                             if ($z[$j!= "\n"$z[$j' ';
  3494.                         }
  3495.                     }
  3496.                 }
  3497.                 for ($j $i$j strlen($z&& $z[$j!= "\n"$j++{
  3498.                     $z[$j' ';
  3499.                 }
  3500.             elseif (substr($z$i6=== "%ifdef" && trim($z[$i+6]=== '' ||
  3501.                       substr($z$i7=== "%ifndef" && trim($z[$i+7]=== ''{
  3502.                 if ($exclude{
  3503.                     $exclude++;
  3504.                 else {
  3505.                     $j $i;
  3506.                     $n strtok(substr($z$j)" \t");
  3507.                     $exclude = 1;
  3508.                     if (isset($this->lemon->azDefine[$n])) {
  3509.                         $exclude = 0;
  3510.                     }
  3511.                     if ($z[$i + 3]=='n'{
  3512.                         // this is a rather obtuse way of checking whether this is %ifndef
  3513.                         $exclude !$exclude;
  3514.                     }
  3515.                     if ($exclude{
  3516.                         $start $i;
  3517.                         $start_lineno $lineno;
  3518.                     }
  3519.                 }
  3520.                 //for ($j = $i; $j < strlen($z) && $z[$j] != "\n"; $j++) $z[$j] = ' ';
  3521.                 $j strpos(substr($z$i)"\n");
  3522.                 if ($j === false{
  3523.                     $z substr($z0$i)// remove instead of adding ' '
  3524.                 else {
  3525.                     $z substr($z0$isubstr($z$i $j)// remove instead of adding ' '
  3526.                 }
  3527.             }
  3528.         }
  3529.         if ($exclude{
  3530.             throw new Exception("unterminated %ifdef starting on line $start_lineno\n");
  3531.         }
  3532.     }
  3533.  
  3534.     /**
  3535.      * In spite of its name, this function is really a scanner.
  3536.      * 
  3537.      * It reads in the entire input file (all at once) then tokenizes it.
  3538.      * Each token is passed to the function "parseonetoken" which builds all
  3539.      * the appropriate data structures in the global state vector "gp".
  3540.      * @param LemonData 
  3541.      */
  3542.     function Parse($gp)
  3543.     {
  3544.         $startline = 0;
  3545.     
  3546.         $this->gp $gp;
  3547.         $this->filename $gp->filename;
  3548.         $this->errorcnt = 0;
  3549.         $this->state = self::INITIALIZE;
  3550.     
  3551.         /* Begin by reading the input file */
  3552.         $filebuf file_get_contents($this->filename);
  3553.         if (!$filebuf{
  3554.             Lemon::ErrorMsg($this->filename0"Can't open this file for reading.");
  3555.             $gp->errorcnt++;
  3556.             return;
  3557.         }
  3558.         if (filesize($this->filename!= strlen($filebuf)) {
  3559.             ErrorMsg($this->filename0"Can't read in all %d bytes of this file.",
  3560.                 filesize($this->filename));
  3561.             $gp->errorcnt++;
  3562.             return;
  3563.         }
  3564.  
  3565.         /* Make an initial pass through the file to handle %ifdef and %ifndef */
  3566.         $this->preprocess_input($filebuf);
  3567.     
  3568.         /* Now scan the text of the input file */
  3569.         $lineno = 1;
  3570.         for ($cp = 0$c $filebuf[0]$cp strlen($filebuf)$cp++{
  3571.             $c $filebuf[$cp];
  3572.             if ($c == "\n"$lineno++;              /* Keep track of the line number */
  3573.             if (trim($c=== ''{
  3574.                 continue;
  3575.             }  /* Skip all white space */
  3576.             if ($filebuf[$cp== '/' && ($cp + 1 < strlen($filebuf)) && $filebuf[$cp + 1== '/'{
  3577.                 /* Skip C++ style comments */
  3578.                 $cp += 2;
  3579.                 $z strpos(substr($filebuf$cp)"\n");
  3580.                 if ($z === false{
  3581.                     $cp strlen($filebuf);
  3582.                     break;
  3583.                 }
  3584.                 $lineno++;
  3585.                 $cp += $z;
  3586.                 continue;
  3587.             }
  3588.             if ($filebuf[$cp== '/' && ($cp + 1 < strlen($filebuf)) && $filebuf[$cp + 1== '*'{
  3589.                 /* Skip C style comments */
  3590.                 $cp += 2;
  3591.                 $z strpos(substr($filebuf$cp)'*/');
  3592.                 if ($z !== false{
  3593.                     $lineno += count(explode("\n"substr($filebuf$cp$z))) - 1;
  3594.                 }
  3595.                 $cp += $z + 1;
  3596.                 continue;
  3597.             }
  3598.             $this->tokenstart $cp;                /* Mark the beginning of the token */
  3599.             $this->tokenlineno $lineno;           /* Linenumber on which token begins */
  3600.             if ($filebuf[$cp== '"'{                     /* String literals */
  3601.                 $cp++;
  3602.                 $oldcp $cp;
  3603.                 $test strpos(substr($filebuf$cp)'"');
  3604.                 if ($test === false{
  3605.                     Lemon::ErrorMsg($this->filename$startline,
  3606.                     "String starting on this line is not terminated before the end of the file.");
  3607.                     $this->errorcnt++;
  3608.                     $nextcp $cp strlen($filebuf);
  3609.                 else {
  3610.                     $cp += $test;
  3611.                     $nextcp $cp + 1;
  3612.                 }
  3613.                 $lineno += count(explode("\n"substr($filebuf$oldcp$cp $oldcp))) - 1;
  3614.             elseif ($filebuf[$cp== '{'{               /* A block of C code */
  3615.                 $cp++;
  3616.                 for ($level = 1; $cp strlen($filebuf&& ($level > 1 || $filebuf[$cp!= '}')$cp++{
  3617.                     if ($filebuf[$cp== "\n"{
  3618.                         $lineno++;
  3619.                     elseif ($filebuf[$cp== '{'{
  3620.                         $level++;
  3621.                     elseif ($filebuf[$cp== '}'{
  3622.                         $level--;
  3623.                     elseif ($filebuf[$cp== '/' && $filebuf[$cp + 1== '*'{
  3624.                         /* Skip comments */
  3625.                         $cp += 2;
  3626.                         $z strpos(substr($filebuf$cp)'*/');
  3627.                         if ($z !== false{
  3628.                             $lineno += count(explode("\n"substr($filebuf$cp$z))) - 1;
  3629.                         }
  3630.                         $cp += $z + 2;
  3631.                     elseif ($filebuf[$cp== '/' && $filebuf[$cp + 1== '/'{
  3632.                         /* Skip C++ style comments too */
  3633.                         $cp += 2;
  3634.                         $z strpos(substr($filebuf$cp)"\n");
  3635.                         if ($z === false{
  3636.                             $cp strlen($filebuf);
  3637.                             break;
  3638.                         else {
  3639.                             $lineno++;
  3640.                         }
  3641.                         $cp += $z;
  3642.                     elseif ($filebuf[$cp== "'" || $filebuf[$cp== '"'{
  3643.                         /* String a character literals */
  3644.                         $startchar $filebuf[$cp];
  3645.                         $prevc = 0;
  3646.                         for ($cp++; $cp strlen($filebuf&& ($filebuf[$cp!= $startchar || $prevc === '\\')$cp++{
  3647.                             if ($filebuf[$cp== "\n"{
  3648.                                 $lineno++;
  3649.                             }
  3650.                             if ($prevc === '\\'{
  3651.                                 $prevc = 0;
  3652.                             else {
  3653.                                 $prevc $filebuf[$cp];
  3654.                             }
  3655.                         }
  3656.                     }
  3657.                 }
  3658.                 if ($cp >= strlen($filebuf)) {
  3659.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3660.                         "PHP code starting on this line is not terminated before the end of the file.");
  3661.                     $this->errorcnt++;
  3662.                     $nextcp $cp;
  3663.                 else {
  3664.                     $nextcp $cp + 1;
  3665.                 }
  3666.             elseif (preg_match('/[a-zA-Z0-9]/'$filebuf[$cp])) {
  3667.                 /* Identifiers */
  3668.                 preg_match('/[a-zA-Z0-9_]+/'substr($filebuf$cp)$preg_results);
  3669.                 $cp += strlen($preg_results[0]);
  3670.                 $nextcp $cp;
  3671.             elseif ($filebuf[$cp== ':' && $filebuf[$cp + 1== ':' &&
  3672.                       $filebuf[$cp + 2== '='{
  3673.                 /* The operator "::=" */
  3674.                 $cp += 3;
  3675.                 $nextcp $cp;
  3676.             elseif (($filebuf[$cp== '/' || $filebuf[$cp== '|'&&
  3677.                       preg_match('/[a-zA-Z]/'$filebuf[$cp + 1])) {
  3678.                 $cp += 2;
  3679.                 preg_match('/[a-zA-Z0-9_]+/'substr($filebuf$cp)$preg_results);
  3680.                 $cp += strlen($preg_results[0]);
  3681.                 $nextcp $cp;
  3682.             else {
  3683.                 /* All other (one character) operators */
  3684.                 $cp ++;
  3685.                 $nextcp $cp;
  3686.             }
  3687.             $this->parseonetoken(substr($filebuf$this->tokenstart,
  3688.                 $cp $this->tokenstart))/* Parse the token */
  3689.             $cp $nextcp - 1;
  3690.         }
  3691.         $gp->rule = $this->firstrule;
  3692.         $gp->errorcnt = $this->errorcnt;
  3693.     }
  3694.  
  3695.     /**
  3696.      * Parse a single token
  3697.      * @param string token
  3698.      */
  3699.     function parseonetoken($token)
  3700.     {
  3701.         $x $token;
  3702.         $this->= 0; // for referencing in WAITING_FOR_DECL_KEYWORD
  3703.         if (DEBUG{
  3704.             printf("%s:%d: Token=[%s] state=%d\n",
  3705.                 $this->filename$this->tokenlineno$token$this->state);
  3706.         }
  3707.         switch ($this->state{
  3708.             case self::INITIALIZE:
  3709.                 $this->prevrule = 0;
  3710.                 $this->preccounter = 0;
  3711.                 $this->firstrule $this->lastrule = 0;
  3712.                 $this->gp->nrule = 0;
  3713.                 /* Fall thru to next case */
  3714.             case self::WAITING_FOR_DECL_OR_RULE:
  3715.                 if ($x[0== '%'{
  3716.                     $this->state = self::WAITING_FOR_DECL_KEYWORD;
  3717.                 elseif (preg_match('/[a-z]/'$x[0])) {
  3718.                     $this->lhs = LemonSymbol::Symbol_new($x);
  3719.                     $this->nrhs = 0;
  3720.                     $this->lhsalias = 0;
  3721.                     $this->state = self::WAITING_FOR_ARROW;
  3722.                 elseif ($x[0== '{'{
  3723.                     if ($this->prevrule === 0{
  3724.                         Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3725.                             "There is no prior rule opon which to attach the code
  3726.                              fragment which begins on this line.");
  3727.                         $this->errorcnt++;
  3728.                     elseif ($this->prevrule->code != 0{
  3729.                         Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3730.                             "Code fragment beginning on this line is not the first \
  3731.                              to follow the previous rule.");
  3732.                         $this->errorcnt++;
  3733.                     else {
  3734.                         $this->prevrule->line = $this->tokenlineno;
  3735.                         $this->prevrule->code = substr($x1);
  3736.                     }
  3737.                 elseif ($x[0== '['{
  3738.                     $this->state = self::PRECEDENCE_MARK_1;
  3739.                 else {
  3740.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3741.                     "Token \"%s\" should be either \"%%\" or a nonterminal name.",
  3742.                     $x);
  3743.                     $this->errorcnt++;
  3744.                 }
  3745.                 break;
  3746.             case self::PRECEDENCE_MARK_1:
  3747.                 if (!preg_match('/[A-Z]/'$x[0])) {
  3748.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3749.                         "The precedence symbol must be a terminal.");
  3750.                     $this->errorcnt++;
  3751.                 elseif ($this->prevrule === 0{
  3752.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3753.                         "There is no prior rule to assign precedence \"[%s]\"."$x);
  3754.                     $this->errorcnt++;
  3755.                 elseif ($this->prevrule->precsym != 0{
  3756.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3757.                         "Precedence mark on this line is not the first to follow the previous rule.");
  3758.                     $this->errorcnt++;
  3759.                 else {
  3760.                     $this->prevrule->precsym = LemonSymbol::Symbol_new($x);
  3761.                 }
  3762.                 $this->state = self::PRECEDENCE_MARK_2;
  3763.                 break;
  3764.             case self::PRECEDENCE_MARK_2:
  3765.                 if ($x[0!= ']'{
  3766.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3767.                         "Missing \"]\" on precedence mark.");
  3768.                     $this->errorcnt++;
  3769.                 }
  3770.                 $this->state = self::WAITING_FOR_DECL_OR_RULE;
  3771.                 break;
  3772.             case self::WAITING_FOR_ARROW:
  3773.                 if ($x[0== ':' && $x[1== ':' && $x[2== '='{
  3774.                     $this->state = self::IN_RHS;
  3775.                 elseif ($x[0== '('{
  3776.                     $this->state = self::LHS_ALIAS_1;
  3777.                 else {
  3778.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3779.                         "Expected to see a \":\" following the LHS symbol \"%s\".",
  3780.                     $this->lhs->name);
  3781.                     $this->errorcnt++;
  3782.                     $this->state = self::RESYNC_AFTER_RULE_ERROR;
  3783.                 }
  3784.                 break;
  3785.             case self::LHS_ALIAS_1:
  3786.                 if (preg_match('/[A-Za-z]/'$x[0])) {
  3787.                     $this->lhsalias $x;
  3788.                     $this->state = self::LHS_ALIAS_2;
  3789.                 else {
  3790.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3791.                         "\"%s\" is not a valid alias for the LHS \"%s\"\n",
  3792.                         $x$this->lhs->name);
  3793.                     $this->errorcnt++;
  3794.                     $this->state = self::RESYNC_AFTER_RULE_ERROR;
  3795.                 }
  3796.                 break;
  3797.             case self::LHS_ALIAS_2:
  3798.                 if ($x[0== ')'{
  3799.                     $this->state = self::LHS_ALIAS_3;
  3800.                 else {
  3801.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3802.                         "Missing \")\" following LHS alias name \"%s\".",$this->lhsalias);
  3803.                     $this->errorcnt++;
  3804.                     $this->state = self::RESYNC_AFTER_RULE_ERROR;
  3805.                 }
  3806.                 break;
  3807.             case self::LHS_ALIAS_3:
  3808.                 if ($x == '::='{
  3809.                     $this->state = self::IN_RHS;
  3810.                 else {
  3811.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3812.                         "Missing \"->\" following: \"%s(%s)\".",
  3813.                     $this->lhs->name$this->lhsalias);
  3814.                     $this->errorcnt++;
  3815.                     $this->state = self::RESYNC_AFTER_RULE_ERROR;
  3816.                 }
  3817.                 break;
  3818.             case self::IN_RHS:
  3819.                 if ($x[0== '.'{
  3820.                     $rp = new LemonRule;
  3821.                     $rp->ruleline = $this->tokenlineno;
  3822.                     for ($i = 0; $i $this->nrhs$i++{
  3823.                         $rp->rhs[$i$this->rhs[$i];
  3824.                         $rp->rhsalias[$i$this->alias[$i];
  3825.                     }
  3826.                     $rp->lhs = $this->lhs;
  3827.                     $rp->lhsalias = $this->lhsalias;
  3828.                     $rp->nrhs = $this->nrhs;
  3829.                     $rp->code = 0;
  3830.                     $rp->precsym = 0;
  3831.                     $rp->index = $this->gp->nrule++;
  3832.                     $rp->nextlhs = $rp->lhs->rule;
  3833.                     $rp->lhs->rule = $rp;
  3834.                     $rp->next = 0;
  3835.                     if ($this->firstrule === 0{
  3836.                         $this->firstrule $this->lastrule $rp;
  3837.                     else {
  3838.                         $this->lastrule->next = $rp;
  3839.                         $this->lastrule $rp;
  3840.                     }
  3841.                     $this->prevrule $rp;
  3842.                     $this->state = self::WAITING_FOR_DECL_OR_RULE;
  3843.                 elseif (preg_match('/[a-zA-Z]/'$x[0])) {
  3844.                     if ($this->nrhs >= Lemon::MAXRHS{
  3845.                         Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3846.                             "Too many symbols on RHS or rule beginning at \"%s\".",
  3847.                             $x);
  3848.                         $this->errorcnt++;
  3849.                         $this->state = self::RESYNC_AFTER_RULE_ERROR;
  3850.                     else {
  3851.                         if (isset($this->rhs[$this->nrhs - 1])) {
  3852.                             $msp $this->rhs[$this->nrhs - 1];
  3853.                             if ($msp->type == LemonSymbol::MULTITERMINAL{
  3854.                                 $inf array_reduce($msp->subsym,
  3855.                                     array($this'_printmulti')'');
  3856.                                 Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3857.                                     'WARNING: symbol ' $x ' will not' .
  3858.                                     ' be part of previous multiterminal %s',
  3859.                                     substr($inf0strlen($inf- 1)
  3860.                                     );
  3861.                             }
  3862.                         }
  3863.                         $this->rhs[$this->nrhs= LemonSymbol::Symbol_new($x);
  3864.                         $this->alias[$this->nrhs= 0;
  3865.                         $this->nrhs++;
  3866.                     }
  3867.                 elseif (($x[0== '|' || $x[0== '/'&& $this->nrhs > 0{
  3868.                     $msp $this->rhs[$this->nrhs - 1];
  3869.                     if ($msp->type != LemonSymbol::MULTITERMINAL{
  3870.                         $origsp $msp;
  3871.                         $msp = new LemonSymbol;
  3872.                         $msp->type = LemonSymbol::MULTITERMINAL;
  3873.                         $msp->nsubsym = 1;
  3874.                         $msp->subsym = array($origsp);
  3875.                         $msp->name = $origsp->name;
  3876.                         $this->rhs[$this->nrhs - 1$msp;
  3877.                     }
  3878.                     $msp->nsubsym++;
  3879.                     $msp->subsym[$msp->nsubsym - 1= LemonSymbol::Symbol_new(substr($x1));
  3880.                     if (preg_match('/[a-z]/'$x[1]||
  3881.                           preg_match('/[a-z]/'$msp->subsym[0]->name[0])) {
  3882.                         Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3883.                         "Cannot form a compound containing a non-terminal");
  3884.                         $this->errorcnt++;
  3885.                     }
  3886.                 elseif ($x[0== '(' && $this->nrhs > 0{
  3887.                     $this->state = self::RHS_ALIAS_1;
  3888.                 else {
  3889.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3890.                         "Illegal character on RHS of rule: \"%s\"."$x);
  3891.                     $this->errorcnt++;
  3892.                     $this->state = self::RESYNC_AFTER_RULE_ERROR;
  3893.                 }
  3894.                 break;
  3895.             case self::RHS_ALIAS_1:
  3896.                 if (preg_match('/[A-Za-z]/'$x[0])) {
  3897.                     $this->alias[$this->nrhs - 1$x;
  3898.                     $this->state = self::RHS_ALIAS_2;
  3899.                 else {
  3900.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3901.                         "\"%s\" is not a valid alias for the RHS symbol \"%s\"\n",
  3902.                         $x$this->rhs[$this->nrhs - 1]->name);
  3903.                     $this->errorcnt++;
  3904.                     $this->state = self::RESYNC_AFTER_RULE_ERROR;
  3905.                 }
  3906.                 break;
  3907.             case self::RHS_ALIAS_2:
  3908.                 if ($x[0== ')'{
  3909.                     $this->state = self::IN_RHS;
  3910.                 else {
  3911.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3912.                         "Missing \")\" following LHS alias name \"%s\"."$this->lhsalias);
  3913.                     $this->errorcnt++;
  3914.                     $this->state = self::RESYNC_AFTER_RULE_ERROR;
  3915.                 }
  3916.                 break;
  3917.             case self::WAITING_FOR_DECL_KEYWORD:
  3918.                 if(preg_match('/[A-Za-z]/'$x[0])) {
  3919.                     $this->declkeyword $x;
  3920.                     $this->declargslot &$this->a;
  3921.                     $this->decllnslot &$this->a;
  3922.                     $this->state = self::WAITING_FOR_DECL_ARG;
  3923.                     if ('name' == $x{
  3924.                         $this->declargslot &$this->gp->name;
  3925.                     elseif ('include' == $x{
  3926.                         $this->declargslot &$this->gp->include_code;
  3927.                         $this->decllnslot &$this->gp->includeln;
  3928.                     elseif ('include_class' == $x{
  3929.                         $this->declargslot &$this->gp->include_classcode;
  3930.                         $this->decllnslot &$this->gp->include_classln;
  3931.                     elseif ('declare_class' == $x{
  3932.                         $this->declargslot &$this->gp->declare_classcode;
  3933.                         $this->decllnslot &$this->gp->declare_classln;
  3934.                     elseif ('code' == $x{
  3935.                         $this->declargslot &$this->gp->extracode;
  3936.                         $this->decllnslot &$this->gp->extracodeln;
  3937.                     elseif ('token_destructor' == $x{
  3938.                         $this->declargslot &$this->gp->tokendest;
  3939.                         $this->decllnslot &$this->gp->tokendestln;
  3940.                     elseif ('default_destructor' == $x{
  3941.                         $this->declargslot &$this->gp->vardest;
  3942.                         $this->decllnslot &$this->gp->vardestln;
  3943.                     elseif ('token_prefix' == $x{
  3944.                         $this->declargslot &$this->gp->tokenprefix;
  3945.                     elseif ('syntax_error' == $x{
  3946.                         $this->declargslot &$this->gp->error;
  3947.                         $this->decllnslot &$this->gp->errorln;
  3948.                     elseif ('parse_accept' == $x{
  3949.                         $this->declargslot &$this->gp->accept;
  3950.                         $this->decllnslot &$this->gp->acceptln;
  3951.                     elseif ('parse_failure' == $x{
  3952.                         $this->declargslot &$this->gp->failure;
  3953.                         $this->decllnslot &$this->gp->failureln;
  3954.                     elseif ('stack_overflow' == $x{
  3955.                         $this->declargslot &$this->gp->overflow;
  3956.                         $this->decllnslot &$this->gp->overflowln;
  3957.                     else if('extra_argument' == $x{
  3958.                         $this->declargslot &$this->gp->arg;
  3959.                     elseif ('token_type' == $x{
  3960.                         $this->declargslot &$this->gp->tokentype;
  3961.                     elseif ('default_type' == $x{
  3962.                         $this->declargslot &$this->gp->vartype;
  3963.                     elseif ('stack_size' == $x{
  3964.                         $this->declargslot &$this->gp->stacksize;
  3965.                     elseif ('start_symbol' == $x{
  3966.                         $this->declargslot &$this->gp->start;
  3967.                     elseif ('left' == $x{
  3968.                         $this->preccounter++;
  3969.                         $this->declassoc = LemonSymbol::LEFT;
  3970.                         $this->state = self::WAITING_FOR_PRECEDENCE_SYMBOL;
  3971.                     elseif ('right' == $x{
  3972.                         $this->preccounter++;
  3973.                         $this->declassoc = LemonSymbol::RIGHT;
  3974.                         $this->state = self::WAITING_FOR_PRECEDENCE_SYMBOL;
  3975.                     elseif ('nonassoc' == $x{
  3976.                         $this->preccounter++;
  3977.                         $this->declassoc = LemonSymbol::NONE;
  3978.                         $this->state = self::WAITING_FOR_PRECEDENCE_SYMBOL;
  3979.                     elseif ('destructor' == $x{
  3980.                         $this->state = self::WAITING_FOR_DESTRUCTOR_SYMBOL;
  3981.                     elseif ('type' == $x{
  3982.                         $this->state = self::WAITING_FOR_DATATYPE_SYMBOL;
  3983.                     elseif ('fallback' == $x{
  3984.                         $this->fallback = 0;
  3985.                         $this->state = self::WAITING_FOR_FALLBACK_ID;
  3986.                     else {
  3987.                         Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3988.                         "Unknown declaration keyword: \"%%%s\"."$x);
  3989.                         $this->errorcnt++;
  3990.                         $this->state = self::RESYNC_AFTER_DECL_ERROR;
  3991.                     }
  3992.                 else {
  3993.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  3994.                         "Illegal declaration keyword: \"%s\"."$x);
  3995.                     $this->errorcnt++;
  3996.                     $this->state = self::RESYNC_AFTER_DECL_ERROR;
  3997.                 }
  3998.                 break;
  3999.             case self::WAITING_FOR_DESTRUCTOR_SYMBOL:
  4000.                 if (!preg_match('/[A-Za-z]/'$x[0])) {
  4001.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  4002.                         "Symbol name missing after %destructor keyword");
  4003.                     $this->errorcnt++;
  4004.                     $this->state = self::RESYNC_AFTER_DECL_ERROR;
  4005.                 else {
  4006.                     $sp = LemonSymbol::Symbol_new($x);
  4007.                     $this->declargslot &$sp->destructor;
  4008.                     $this->decllnslot &$sp->destructorln;
  4009.                     $this->state = self::WAITING_FOR_DECL_ARG;
  4010.                 }
  4011.                 break;
  4012.             case self::WAITING_FOR_DATATYPE_SYMBOL:
  4013.                 if (!preg_match('/[A-Za-z]/'$x[0])) {
  4014.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  4015.                         "Symbol name missing after %destructor keyword");
  4016.                     $this->errorcnt++;
  4017.                     $this->state = self::RESYNC_AFTER_DECL_ERROR;
  4018.                 else {
  4019.                     $sp = LemonSymbol::Symbol_new($x);
  4020.                     $this->declargslot &$sp->datatype;
  4021.                     $this->state = self::WAITING_FOR_DECL_ARG;
  4022.                 }
  4023.                 break;
  4024.             case self::WAITING_FOR_PRECEDENCE_SYMBOL:
  4025.                 if ($x[0== '.'{
  4026.                     $this->state = self::WAITING_FOR_DECL_OR_RULE;
  4027.                 elseif (preg_match('/[A-Z]/'$x[0])) {
  4028.                     $sp = LemonSymbol::Symbol_new($x);
  4029.                     if ($sp->prec >= 0{
  4030.                         Lemon::ErrorMsg($this->filename$this->tokenlineno,
  4031.                             "Symbol \"%s\" has already been given a precedence."$x);
  4032.                         $this->errorcnt++;
  4033.                     else {
  4034.                         $sp->prec = $this->preccounter;
  4035.                         $sp->assoc = $this->declassoc;
  4036.                     }
  4037.                 else {
  4038.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  4039.                         "Can't assign a precedence to \"%s\"."$x);
  4040.                     $this->errorcnt++;
  4041.                 }
  4042.                 break;
  4043.             case self::WAITING_FOR_DECL_ARG:
  4044.                 if (preg_match('/[A-Za-z0-9{"]/'$x[0])) {
  4045.                     if ($this->declargslot != 0{
  4046.                         Lemon::ErrorMsg($this->filename$this->tokenlineno,
  4047.                             "The argument \"%s\" to declaration \"%%%s\" is not the first.",
  4048.                             $x[0== '"' substr($x1$x$this->declkeyword);
  4049.                         $this->errorcnt++;
  4050.                         $this->state = self::RESYNC_AFTER_DECL_ERROR;
  4051.                     else {
  4052.                         $this->declargslot ($x[0== '"' || $x[0== '{'substr($x1$x;
  4053.                         $this->= 1;
  4054.                         if (!$this->decllnslot{
  4055.                             $this->decllnslot $this->tokenlineno;
  4056.                         }
  4057.                         $this->state = self::WAITING_FOR_DECL_OR_RULE;
  4058.                     }
  4059.                 else {
  4060.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  4061.                         "Illegal argument to %%%s: %s",$this->declkeyword$x);
  4062.                     $this->errorcnt++;
  4063.                     $this->state = self::RESYNC_AFTER_DECL_ERROR;
  4064.                 }
  4065.                 break;
  4066.             case self::WAITING_FOR_FALLBACK_ID:
  4067.                 if ($x[0== '.'{
  4068.                     $this->state = self::WAITING_FOR_DECL_OR_RULE;
  4069.                 elseif (!preg_match('/[A-Z]/'$x[0])) {
  4070.                     Lemon::ErrorMsg($this->filename$this->tokenlineno,
  4071.                     "%%fallback argument \"%s\" should be a token"$x);
  4072.                     $this->errorcnt++;
  4073.                 else {
  4074.                     $sp = LemonSymbol::Symbol_new($x);
  4075.                     if ($this->fallback === 0{
  4076.                         $this->fallback $sp;
  4077.                     elseif (is_object($sp->fallback)) {
  4078.                         Lemon::ErrorMsg($this->filename$this->tokenlineno,
  4079.                         "More than one fallback assigned to token %s"$x);
  4080.                         $this->errorcnt++;
  4081.                     else {
  4082.                         $sp->fallback = $this->fallback;
  4083.                         $this->gp->has_fallback = 1;
  4084.                     }
  4085.                 }
  4086.                 break;
  4087.             case self::RESYNC_AFTER_RULE_ERROR:
  4088.             /*      if ($x[0] == '.') $this->state = self::WAITING_FOR_DECL_OR_RULE;
  4089.             **      break; */
  4090.             case self::RESYNC_AFTER_DECL_ERROR:
  4091.                 if ($x[0== '.'{
  4092.                     $this->state = self::WAITING_FOR_DECL_OR_RULE;
  4093.                 }
  4094.                 if ($x[0== '%'{
  4095.                     $this->state = self::WAITING_FOR_DECL_KEYWORD;
  4096.                 }
  4097.                 break;
  4098.         }
  4099.     }
  4100.  
  4101.     function _printmulti($a$b)
  4102.     {
  4103.         if (!$a{
  4104.             $a '';
  4105.         }
  4106.         $a .= $b->name . '|';
  4107.         return $a;
  4108.     }
  4109. }
  4110. $a = new Lemon;
  4111. $_SERVER['argv'= array('lemon''-s''/development/lemon/PHP_Parser.y');
  4112. //$_SERVER['argv'] = array('lemon', '-s', '/development/File_ChessPGN/ChessPGN/Parser.y');
  4113. $a->main();

Documentation generated on Mon, 11 Mar 2019 15:40:59 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.