/** * @return PHP_ParserGenerator_State */ private function getstate() { /* Extract the sorted basis of the new state. The basis was constructed ** by prior calls to "Configlist_addbasis()". */ PHP_ParserGenerator_Config::Configlist_sortbasis(); $bp = PHP_ParserGenerator_Config::Configlist_basis(); /* Get a state with the same basis */ $stp = PHP_ParserGenerator_State::State_find($bp); if ($stp) { /* A state with the same basis already exists! Copy all the follow-set ** propagation links from the state under construction into the ** preexisting state, then return a pointer to the preexisting state */ for ($x = $bp, $y = $stp->bp; $x && $y; $x = $x->bp, $y = $y->bp) { PHP_ParserGenerator_PropagationLink::Plink_copy($y->bplp, $x->bplp); PHP_ParserGenerator_PropagationLink::Plink_delete($x->fplp); $x->fplp = $x->bplp = 0; } $cfp = PHP_ParserGenerator_Config::Configlist_return(); PHP_ParserGenerator_Config::Configlist_eat($cfp); } else { /* This really is a new state. Construct all the details */ PHP_ParserGenerator_Config::Configlist_closure($this); /* Compute the configuration closure */ PHP_ParserGenerator_Config::Configlist_sort(); /* Sort the configuration closure */ $cfp = PHP_ParserGenerator_Config::Configlist_return(); /* Get a pointer to the config list */ $stp = new PHP_ParserGenerator_State(); /* A new state structure */ $stp->bp = $bp; /* Remember the configuration basis */ $stp->cfp = $cfp; /* Remember the configuration closure */ $stp->statenum = $this->nstate++; /* Every state gets a sequence number */ $stp->ap = 0; /* No actions, yet. */ PHP_ParserGenerator_State::State_insert($stp, $stp->bp); /* Add to the state table */ // this can't work, recursion is too deep, move it into FindStates() //$this->buildshifts($stp); /* Recursively compute successor states */ return array($stp); } return $stp; }
function main() { $lem = new PHP_ParserGenerator_Data(); $this->OptInit($_SERVER['argv']); if ($this->version) { echo "Lemon version 1.0/PHP_ParserGenerator port version 0.1.5\n"; exit(0); } if ($this->OptNArgs($_SERVER['argv']) != 1) { echo "Exactly one filename argument is required.\n"; exit(1); } $lem->errorcnt = 0; /* Initialize the machine */ $lem->argv0 = $_SERVER['argv'][0]; $lem->filename = $this->OptArg(0, $_SERVER['argv']); $a = pathinfo($lem->filename); if (isset($a['extension'])) { $ext = '.' . $a['extension']; $lem->filenosuffix = substr($lem->filename, 0, strlen($lem->filename) - strlen($ext)); } else { $lem->filenosuffix = $lem->filename; } $lem->basisflag = $this->basisflag; $lem->has_fallback = 0; $lem->nconflict = 0; $lem->name = $lem->include_code = $lem->include_classcode = $lem->arg = $lem->tokentype = $lem->start = 0; $lem->vartype = 0; $lem->stacksize = 0; $lem->error = $lem->overflow = $lem->failure = $lem->accept = $lem->tokendest = $lem->tokenprefix = $lem->outname = $lem->extracode = 0; $lem->vardest = 0; $lem->tablesize = 0; PHP_ParserGenerator_Symbol::Symbol_new("\$"); $lem->errsym = PHP_ParserGenerator_Symbol::Symbol_new("error"); /* Parse the input file */ $parser = new PHP_ParserGenerator_Parser($this); $parser->Parse($lem); if ($lem->errorcnt) { exit($lem->errorcnt); } if ($lem->rule === 0) { printf("Empty grammar.\n"); exit(1); } /* Count and index the symbols of the grammar */ $lem->nsymbol = PHP_ParserGenerator_Symbol::Symbol_count(); PHP_ParserGenerator_Symbol::Symbol_new("{default}"); $lem->symbols = PHP_ParserGenerator_Symbol::Symbol_arrayof(); for ($i = 0; $i <= $lem->nsymbol; $i++) { $lem->symbols[$i]->index = $i; } usort($lem->symbols, array('PHP_ParserGenerator_Symbol', 'sortSymbols')); for ($i = 0; $i <= $lem->nsymbol; $i++) { $lem->symbols[$i]->index = $i; } // find the first lower-case symbol for ($i = 1; ord($lem->symbols[$i]->name[0]) < ord('Z'); $i++) { } $lem->nterminal = $i; /* Generate a reprint of the grammar, if requested on the command line */ if ($this->rpflag) { $this->Reprint(); } else { /* Initialize the size for all follow and first sets */ $this->SetSize($lem->nterminal); /* Find the precedence for every production rule (that has one) */ $lem->FindRulePrecedences(); /* Compute the lambda-nonterminals and the first-sets for every ** nonterminal */ $lem->FindFirstSets(); /* Compute all LR(0) states. Also record follow-set propagation ** links so that the follow-set can be computed later */ $lem->nstate = 0; $lem->FindStates(); $lem->sorted = PHP_ParserGenerator_State::State_arrayof(); /* Tie up loose ends on the propagation links */ $lem->FindLinks(); /* Compute the follow set of every reducible configuration */ $lem->FindFollowSets(); /* Compute the action tables */ $lem->FindActions(); /* Compress the action tables */ if ($this->compress === 0) { $lem->CompressTables(); } /* Reorder and renumber the states so that states with fewer choices ** occur at the end. */ $lem->ResortStates(); /* Generate a report of the parser generated. (the "y.output" file) */ if (!$this->quiet) { $lem->ReportOutput(); } /* Generate the source code for the parser */ $lem->ReportTable($this->mhflag); /* Produce a header file for use by the scanner. (This step is ** omitted if the "-m" option is used because makeheaders will ** generate the file for us.) */ // if (!$this->mhflag) { // $this->ReportHeader(); // } } if ($this->statistics) { printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n", $lem->nterminal, $lem->nsymbol - $lem->nterminal, $lem->nrule); printf(" %d states, %d parser table entries, %d conflicts\n", $lem->nstate, $lem->tablesize, $lem->nconflict); } if ($lem->nconflict) { printf("%d parsing conflicts.\n", $lem->nconflict); } exit($lem->errorcnt + $lem->nconflict); return $lem->errorcnt + $lem->nconflict; }