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

Source for file Data.php

Documentation is available at Data.php

  1. <?php
  2. /**
  3.  * PHP_ParserGenerator, a php 5 parser generator.
  4.  * 
  5.  * This is a direct port of the Lemon parser generator, found at
  6.  * {@link http://www.hwaci.com/sw/lemon/}
  7.  *
  8.  * PHP version 5
  9.  *
  10.  * LICENSE:
  11.  * 
  12.  * Copyright (c) 2006, Gregory Beaver <cellog@php.net>
  13.  * All rights reserved.
  14.  *
  15.  * Redistribution and use in source and binary forms, with or without
  16.  * modification, are permitted provided that the following conditions
  17.  * are met:
  18.  *
  19.  *     * Redistributions of source code must retain the above copyright
  20.  *       notice, this list of conditions and the following disclaimer.
  21.  *     * Redistributions in binary form must reproduce the above copyright
  22.  *       notice, this list of conditions and the following disclaimer in
  23.  *       the documentation and/or other materials provided with the distribution.
  24.  *     * Neither the name of the PHP_ParserGenerator nor the names of its
  25.  *       contributors may be used to endorse or promote products derived
  26.  *       from this software without specific prior written permission.
  27.  *
  28.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  29.  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  30.  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  31.  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  32.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  33.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  34.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  35.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  36.  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  37.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  38.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  39.  *
  40.  * @category   php
  41.  * @package    PHP_ParserGenerator
  42.  * @author     Gregory Beaver <cellog@php.net>
  43.  * @copyright  2006 Gregory Beaver
  44.  * @license    http://www.opensource.org/licenses/bsd-license.php New BSD License
  45.  * @version    CVS: $Id$
  46.  * @since      File available since Release 0.1.0
  47.  */
  48. /**
  49. /**
  50.  * The state vector for the entire parser generator is recorded in
  51.  * this class.
  52.  * 
  53.  * @package    PHP_ParserGenerator
  54.  * @author     Gregory Beaver <cellog@php.net>
  55.  * @copyright  2006 Gregory Beaver
  56.  * @license    http://www.opensource.org/licenses/bsd-license.php New BSD License
  57.  * @version    @package_version@
  58.  * @since      Class available since Release 0.1.0
  59.  */
  60.  
  61. {
  62.     /**
  63.      * Used for terminal and non-terminal offsets into the action table
  64.      * when their default should be used instead
  65.      */
  66.     const NO_OFFSET = -2147483647;
  67.     /**
  68.      * Table of states sorted by state number
  69.      * @var array array of {@link PHP_ParserGenerator_State} objects
  70.      */
  71.     public $sorted;
  72.     /**
  73.      * List of all rules
  74.      * @var PHP_ParserGenerator_Rule 
  75.      */
  76.     public $rule;
  77.     /**
  78.      * Number of states
  79.      * @var int 
  80.      */
  81.     public $nstate;
  82.     /**
  83.      * Number of rules
  84.      * @var int 
  85.      */
  86.     public $nrule;
  87.     /**
  88.      * Number of terminal and nonterminal symbols
  89.      * @var int 
  90.      */
  91.     public $nsymbol;
  92.     /**
  93.      * Number of terminal symbols (tokens)
  94.      * @var int 
  95.      */
  96.     public $nterminal;
  97.     /**
  98.      * Sorted array of pointers to symbols
  99.      * @var array array of {@link PHP_ParserGenerator_Symbol} objects
  100.      */
  101.     public $symbols = array();
  102.     /**
  103.      * Number of errors
  104.      * @var int 
  105.      */
  106.     public $errorcnt;
  107.     /**
  108.      * The error symbol
  109.      * @var PHP_ParserGenerator_Symbol 
  110.      */
  111.     public $errsym;
  112.     /**
  113.      * Name of the generated parser
  114.      * @var string 
  115.      */
  116.     public $name;
  117.     /**
  118.      * Unused relic from the C version
  119.      * 
  120.      * Type of terminal symbols in the parser stack
  121.      * @var string 
  122.      */
  123.     public $tokentype;
  124.     /**
  125.      * Unused relic from the C version
  126.      * 
  127.      * The default type of non-terminal symbols
  128.      * @var string 
  129.      */
  130.     public $vartype;
  131.     /**
  132.      * Name of the start symbol for the grammar
  133.      * @var string 
  134.      */
  135.     public $start;
  136.     /**
  137.      * Size of the parser stack
  138.      * 
  139.      * This is 100 by default, but is set with the %stack_size directive
  140.      * @var int 
  141.      */
  142.     public $stacksize;
  143.     /**
  144.      * Code to put at the start of the parser file
  145.      * 
  146.      * This is set by the %include directive
  147.      * @var string 
  148.      */
  149.     public $include_code;
  150.     /**
  151.      * Line number for start of include code
  152.      * @var int 
  153.      */
  154.     public $includeln;
  155.     /**
  156.      * Code to put in the parser class
  157.      * 
  158.      * This is set by the %include_class directive
  159.      * @var string 
  160.      */
  161.     public $include_classcode;
  162.     /**
  163.      * Line number for start of include code
  164.      * @var int 
  165.      */
  166.     public $include_classln;
  167.     /**
  168.      * any extends/implements code
  169.      * 
  170.      * This is set by the %declare_class directive
  171.      * @var string 
  172.      */
  173.     /**
  174.      * Line number for class declaration code
  175.      * @var int 
  176.      */
  177.     public $declare_classcode;
  178.     /**
  179.      * Line number for start of class declaration code
  180.      * @var int 
  181.      */
  182.     public $declare_classln;
  183.     /**
  184.      * Code to execute when a syntax error is seen
  185.      * 
  186.      * This is set by the %syntax_error directive
  187.      * @var string 
  188.      */
  189.     public $error;
  190.     /**
  191.      * Line number for start of error code
  192.      * @var int 
  193.      */
  194.     public $errorln;
  195.     /**
  196.      * Code to execute on a stack overflow
  197.      * 
  198.      * This is set by the %stack_overflow directive
  199.      */
  200.     public $overflow;
  201.     /**
  202.      * Line number for start of overflow code
  203.      * @var int 
  204.      */
  205.     public $overflowln;
  206.     /**
  207.      * Code to execute on parser failure
  208.      * 
  209.      * This is set by the %parse_failure directive
  210.      * @var string 
  211.      */
  212.     public $failure;
  213.     /**
  214.      * Line number for start of failure code
  215.      * @var int 
  216.      */
  217.     public $failureln;
  218.     /**
  219.      * Code to execute when the parser acccepts (completes parsing)
  220.      * 
  221.      * This is set by the %parse_accept directive
  222.      * @var string 
  223.      */
  224.     public $accept;
  225.     /**
  226.      * Line number for the start of accept code
  227.      * @var int 
  228.      */
  229.     public $acceptln;
  230.     /**
  231.      * Code appended to the generated file
  232.      * 
  233.      * This is set by the %code directive
  234.      * @var string 
  235.      */
  236.     public $extracode;
  237.     /**
  238.      * Line number for the start of the extra code
  239.      * @var int 
  240.      */
  241.     public $extracodeln;
  242.     /**
  243.      * Code to execute to destroy token data
  244.      * 
  245.      * This is set by the %token_destructor directive
  246.      * @var string 
  247.      */
  248.     public $tokendest;
  249.     /**
  250.      * Line number for token destroyer code
  251.      * @var int 
  252.      */
  253.     public $tokendestln;
  254.     /**
  255.      * Code for the default non-terminal destructor
  256.      * 
  257.      * This is set by the %default_destructor directive
  258.      * @var string 
  259.      */
  260.     public $vardest;
  261.     /**
  262.      * Line number for default non-terminal destructor code
  263.      * @var int 
  264.      */
  265.     public $vardestln;
  266.     /**
  267.      * Name of the input file
  268.      * @var string 
  269.      */
  270.     public $filename;
  271.     /**
  272.      * Name of the input file without its extension
  273.      * @var string 
  274.      */
  275.     public $filenosuffix;
  276.     /**
  277.      * Name of the current output file
  278.      * @var string 
  279.      */
  280.     public $outname;
  281.     /**
  282.      * A prefix added to token names
  283.      * @var string 
  284.      */
  285.     public $tokenprefix;
  286.     /**
  287.      * Number of parsing conflicts
  288.      * @var int 
  289.      */
  290.     public $nconflict;
  291.     /**
  292.      * Size of the parse tables
  293.      * @var int 
  294.      */
  295.     public $tablesize;
  296.     /**
  297.      * Public only basis configurations
  298.      */
  299.     public $basisflag;
  300.     /**
  301.      * True if any %fallback is seen in the grammer
  302.      * @var boolean 
  303.      */
  304.     public $has_fallback;
  305.     /**
  306.      * Name of the program
  307.      * @var string 
  308.      */
  309.     public $argv0;
  310.  
  311.     /* Find a precedence symbol of every rule in the grammar.
  312.      * 
  313.      * Those rules which have a precedence symbol coded in the input
  314.      * grammar using the "[symbol]" construct will already have the
  315.      * $rp->precsym field filled.  Other rules take as their precedence
  316.      * symbol the first RHS symbol with a defined precedence.  If there
  317.      * are not RHS symbols with a defined precedence, the precedence
  318.      * symbol field is left blank.
  319.      */
  320.     function FindRulePrecedences()
  321.     {
  322.         for ($rp $this->rule$rp$rp $rp->next{
  323.             if ($rp->precsym === 0{
  324.                 for ($i 0$i $rp->nrhs && $rp->precsym === 0$i++{
  325.                     $sp $rp->rhs[$i];
  326.                     if ($sp->type == PHP_ParserGenerator_Symbol::MULTITERMINAL{
  327.                         for ($j 0$j $sp->nsubsym$j++{
  328.                             if ($sp->subsym[$j]->prec >= 0{
  329.                                 $rp->precsym $sp->subsym[$j];
  330.                                 break;
  331.                             }
  332.                         }
  333.                     elseif ($sp->prec >= 0{
  334.                         $rp->precsym $rp->rhs[$i];
  335.                     }
  336.                 }
  337.             }
  338.         }
  339.     }
  340.  
  341.     /**
  342.      * Find all nonterminals which will generate the empty string.
  343.      * Then go back and compute the first sets of every nonterminal.
  344.      * The first set is the set of all terminal symbols which can begin
  345.      * a string generated by that nonterminal.
  346.      */
  347.     function FindFirstSets()
  348.     {
  349.         for ($i 0$i $this->nsymbol$i++{
  350.             $this->symbols[$i]->lambda false;
  351.         }
  352.         for($i $this->nterminal$i $this->nsymbol$i++{
  353.             $this->symbols[$i]->firstset array();
  354.         }
  355.  
  356.         /* First compute all lambdas */
  357.         do{
  358.             $progress 0;
  359.             for ($rp $this->rule$rp$rp $rp->next{
  360.                 if ($rp->lhs->lambda{
  361.                     continue;
  362.                 }
  363.                 for ($i 0$i $rp->nrhs$i++{
  364.                     $sp $rp->rhs[$i];
  365.                     if ($sp->type != PHP_ParserGenerator_Symbol::TERMINAL || $sp->lambda === false{
  366.                         break;
  367.                     }
  368.                 }
  369.                 if ($i === $rp->nrhs{
  370.                     $rp->lhs->lambda true;
  371.                     $progress 1;
  372.                 }
  373.             }
  374.         while ($progress);
  375.  
  376.         /* Now compute all first sets */
  377.         do {
  378.             $progress 0;
  379.             for ($rp $this->rule$rp$rp $rp->next{
  380.                 $s1 $rp->lhs;
  381.                 for ($i 0$i $rp->nrhs$i++{
  382.                     $s2 $rp->rhs[$i];
  383.                     if ($s2->type == PHP_ParserGenerator_Symbol::TERMINAL{
  384.                         //progress += SetAdd(s1->firstset,s2->index);
  385.                         $progress += isset($s1->firstset[$s2->index]1;
  386.                         $s1->firstset[$s2->index1;
  387.                         break;
  388.                     elseif ($s2->type == PHP_ParserGenerator_Symbol::MULTITERMINAL{
  389.                         for ($j 0$j $s2->nsubsym$j++{
  390.                             //progress += SetAdd(s1->firstset,s2->subsym[j]->index);
  391.                             $progress += isset($s1->firstset[$s2->subsym[$j]->index]1;
  392.                             $s1->firstset[$s2->subsym[$j]->index1;
  393.                         }
  394.                         break;
  395.                     elseif ($s1 === $s2{
  396.                         if ($s1->lambda === false{
  397.                             break;
  398.                         }
  399.                     else {
  400.                         //progress += SetUnion(s1->firstset,s2->firstset);
  401.                         $test array_diff_key($s2->firstset$s1->firstset);
  402.                         if (count($test)) {
  403.                             $progress++;
  404.                             $s1->firstset += $test;
  405.                         }
  406.                         if ($s2->lambda === false{
  407.                             break;
  408.                         }
  409.                     }
  410.                 }
  411.             }
  412.         while ($progress);
  413.     }
  414.  
  415.     /**
  416.      * Compute all LR(0) states for the grammar.  Links
  417.      * are added to between some states so that the LR(1) follow sets
  418.      * can be computed later.
  419.      */
  420.     function FindStates()
  421.     {
  422.     
  423.         /* Find the start symbol */
  424.         if ($this->start{
  425.             $sp PHP_ParserGenerator_Symbol::Symbol_find($this->start);
  426.             if ($sp == 0{
  427.                 PHP_ParserGenerator::ErrorMsg($this->filename0,
  428.                     "The specified start symbol \"%s\" is not " .
  429.                     "in a nonterminal of the grammar.  \"%s\" will be used as the start " .
  430.                     "symbol instead."$this->start$this->rule->lhs->name);
  431.                 $this->errorcnt++;
  432.                 $sp $this->rule->lhs;
  433.             }
  434.         else {
  435.             $sp $this->rule->lhs;
  436.         }
  437.     
  438.         /* Make sure the start symbol doesn't occur on the right-hand side of
  439.         ** any rule.  Report an error if it does.  (YACC would generate a new
  440.         ** start symbol in this case.) */
  441.         for ($rp $this->rule$rp$rp $rp->next{
  442.             for ($i 0$i $rp->nrhs$i++{
  443.                 if ($rp->rhs[$i]->type == PHP_ParserGenerator_Symbol::MULTITERMINAL{
  444.                     foreach ($rp->rhs[$i]->subsym as $subsp{
  445.                         if ($subsp === $sp{
  446.                             PHP_ParserGenerator::ErrorMsg($this->filename0,
  447.                                 "The start symbol \"%s\" occurs on the " .
  448.                                 "right-hand side of a rule. This will result in a parser which " .
  449.                                 "does not work properly."$sp->name);
  450.                             $this->errorcnt++;
  451.                         }
  452.                     }
  453.                 elseif ($rp->rhs[$i=== $sp{
  454.                     PHP_ParserGenerator::ErrorMsg($this->filename0,
  455.                         "The start symbol \"%s\" occurs on the " .
  456.                         "right-hand side of a rule. This will result in a parser which " .
  457.                         "does not work properly."$sp->name);
  458.                     $this->errorcnt++;
  459.                 }
  460.             }
  461.         }
  462.     
  463.         /* The basis configuration set for the first state
  464.         ** is all rules which have the start symbol as their
  465.         ** left-hand side */
  466.         for ($rp $sp->rule$rp$rp $rp->nextlhs{
  467.             $newcfp PHP_ParserGenerator_Config::Configlist_addbasis($rp0);
  468.             $newcfp->fws[01;
  469.         }
  470.     
  471.         /* Compute the first state.  All other states will be
  472.         ** computed automatically during the computation of the first one.
  473.         ** The returned pointer to the first state is not used. */
  474.         $newstp array();
  475.         $newstp $this->getstate();
  476.         if (is_array($newstp)) {
  477.             $this->buildshifts($newstp[0])/* Recursively compute successor states */
  478.         }
  479.     }
  480.  
  481.     /**
  482.      * @return PHP_ParserGenerator_State 
  483.      */
  484.     private function getstate()
  485.     {
  486.         /* Extract the sorted basis of the new state.  The basis was constructed
  487.         ** by prior calls to "Configlist_addbasis()". */
  488.         $bp PHP_ParserGenerator_Config::Configlist_basis();
  489.     
  490.         /* Get a state with the same basis */
  491.         $stp PHP_ParserGenerator_State::State_find($bp);
  492.         if ($stp{
  493.             /* A state with the same basis already exists!  Copy all the follow-set
  494.             ** propagation links from the state under construction into the
  495.             ** preexisting state, then return a pointer to the preexisting state */
  496.             for($x $bp$y $stp->bp$x && $y$x $x->bp$y $y->bp{
  497.                 PHP_ParserGenerator_PropagationLink::Plink_copy($y->bplp$x->bplp);
  498.                 PHP_ParserGenerator_PropagationLink::Plink_delete($x->fplp);
  499.                 $x->fplp $x->bplp 0;
  500.             }
  501.             $cfp PHP_ParserGenerator_Config::Configlist_return();
  502.             PHP_ParserGenerator_Config::Configlist_eat($cfp);
  503.         else {
  504.             /* This really is a new state.  Construct all the details */
  505.             PHP_ParserGenerator_Config::Configlist_closure($this);    /* Compute the configuration closure */
  506.             PHP_ParserGenerator_Config::Configlist_sort();           /* Sort the configuration closure */
  507.             $cfp PHP_ParserGenerator_Config::Configlist_return();   /* Get a pointer to the config list */
  508.             $stp new PHP_ParserGenerator_State;           /* A new state structure */
  509.             $stp->bp $bp;                /* Remember the configuration basis */
  510.             $stp->cfp $cfp;              /* Remember the configuration closure */
  511.             $stp->statenum $this->nstate++/* Every state gets a sequence number */
  512.             $stp->ap 0;                 /* No actions, yet. */
  513.             PHP_ParserGenerator_State::State_insert($stp$stp->bp);   /* Add to the state table */
  514.             // this can't work, recursion is too deep, move it into FindStates()
  515.             //$this->buildshifts($stp);       /* Recursively compute successor states */
  516.             return array($stp);
  517.         }
  518.         return $stp;
  519.     }
  520.  
  521.     /**
  522.      * Construct all successor states to the given state.  A "successor"
  523.      * state is any state which can be reached by a shift action.
  524.      * @param PHP_ParserGenerator_Data 
  525.      * @param PHP_ParserGenerator_State The state from which successors are computed
  526.      */