Esempio n. 1
0
 /**
  * {@inheritDoc}
  */
 public function parse(TokenStream $stream)
 {
     $stateStack = array($currentState = 0);
     $args = array();
     foreach ($stream as $token) {
         while (true) {
             $type = $token->getType();
             if (!isset($this->parseTable['action'][$currentState][$type])) {
                 // unexpected token
                 throw new UnexpectedTokenException($token, array_keys($this->parseTable['action'][$currentState]));
             }
             $action = $this->parseTable['action'][$currentState][$type];
             if ($action > 0) {
                 // shift
                 $args[] = $token;
                 $stateStack[] = $currentState = $action;
                 break;
             } elseif ($action < 0) {
                 // reduce
                 $rule = $this->grammar->getRule(-$action);
                 $popCount = count($rule->getComponents());
                 array_splice($stateStack, -$popCount);
                 $newArgs = array_splice($args, -$popCount);
                 if ($callback = $rule->getCallback()) {
                     $args[] = call_user_func_array($callback, $newArgs);
                 } else {
                     $args[] = $newArgs[0];
                 }
                 $state = $stateStack[count($stateStack) - 1];
                 $stateStack[] = $currentState = $this->parseTable['goto'][$state][$rule->getName()];
             } else {
                 // accept
                 return $args[0];
             }
         }
     }
 }
Esempio n. 2
0
 protected function writeAction($trigger, $action)
 {
     if ($action > 0) {
         $this->writer->writeLine(sprintf('// on %s shift and go to state %d', $trigger, $action));
     } elseif ($action < 0) {
         $rule = $this->grammar->getRule(-$action);
         $components = $rule->getComponents();
         if (empty($components)) {
             $rhs = '/* empty */';
         } else {
             $rhs = implode(' ', $components);
         }
         $this->writer->writeLine(sprintf('// on %s reduce by rule %s -> %s', $trigger, $rule->getName(), $rhs));
     } else {
         $this->writer->writeLine(sprintf('// on %s accept the input', $trigger));
     }
     $this->writer->writeLine(sprintf("'%s' => %d,", $trigger, $action));
 }
Esempio n. 3
0
 /**
  * Encodes the handle-finding FSA as a LR parse table.
  *
  * @param \Dissect\Parser\LALR1\Analysis\Automaton $automaton
  *
  * @return array The parse table.
  */
 protected function buildParseTable(Automaton $automaton, Grammar $grammar)
 {
     $nonterminals = array_keys($grammar->getGroupedRules());
     $conflictsMode = $grammar->getConflictsMode();
     $conflicts = array();
     // initialize the table
     $table = array('action' => array(), 'goto' => array());
     foreach ($automaton->getTransitionTable() as $num => $transitions) {
         foreach ($transitions as $trigger => $destination) {
             if (!in_array($trigger, $nonterminals)) {
                 // terminal implies shift
                 $table['action'][$num][$trigger] = $destination;
             } else {
                 // nonterminal goes in the goto table
                 $table['goto'][$num][$trigger] = $destination;
             }
         }
     }
     foreach ($automaton->getStates() as $num => $state) {
         if (!isset($table['action'][$num])) {
             $table['action'][$num] = array();
         }
         foreach ($state->getItems() as $item) {
             if ($item->isReduceItem()) {
                 $ruleNumber = $item->getRule()->getNumber();
                 foreach ($item->getLookahead() as $token) {
                     if (array_key_exists($token, $table['action'][$num])) {
                         // conflict
                         $instruction = $table['action'][$num][$token];
                         if ($instruction > 0) {
                             // s/r
                             if ($conflictsMode & Grammar::SHIFT) {
                                 $conflicts[] = array('state' => $num, 'lookahead' => $token, 'rule' => $item->getRule(), 'resolution' => Grammar::SHIFT);
                                 continue;
                             } else {
                                 throw new ShiftReduceConflictException($num, $item->getRule(), $token, $automaton);
                             }
                         } else {
                             // r/r
                             $originalRule = $grammar->getRule(-$instruction);
                             $newRule = $item->getRule();
                             if ($conflictsMode & Grammar::LONGER_REDUCE) {
                                 $count1 = count($originalRule->getComponents());
                                 $count2 = count($newRule->getComponents());
                                 if ($count1 > $count2) {
                                     // original rule is longer
                                     $resolvedRules = array($originalRule, $newRule);
                                     $conflicts[] = array('state' => $num, 'lookahead' => $token, 'rules' => $resolvedRules, 'resolution' => Grammar::LONGER_REDUCE);
                                     continue;
                                 } elseif ($count2 > $count1) {
                                     // new rule is longer
                                     $table['action'][$num][$token] = -$ruleNumber;
                                     $resolvedRules = array($newRule, $originalRule);
                                     $conflicts[] = array('state' => $num, 'lookahead' => $token, 'rules' => $resolvedRules, 'resolution' => Grammar::LONGER_REDUCE);
                                     continue;
                                 }
                             }
                             if ($conflictsMode & Grammar::EARLIER_REDUCE) {
                                 if (-$instruction < $ruleNumber) {
                                     // original rule was earlier
                                     $resolvedRules = array($originalRule, $newRule);
                                     $conflicts[] = array('state' => $num, 'lookahead' => $token, 'rules' => $resolvedRules, 'resolution' => Grammar::EARLIER_REDUCE);
                                     continue;
                                 } else {
                                     // new rule was earlier
                                     $table['action'][$num][$token] = -$ruleNumber;
                                     $conflicts[] = array('state' => $num, 'lookahead' => $token, 'rules' => $resolvedRules, 'resolution' => Grammar::EARLIER_REDUCE);
                                     $resolvedRules = array($newRule, $originalRule);
                                     continue;
                                 }
                             }
                             // everything failed, throw an exception
                             throw new ReduceReduceConflictException($num, $originalRule, $newRule, $token, $automaton);
                         }
                     }
                     $table['action'][$num][$token] = -$ruleNumber;
                 }
             }
         }
     }
     return array($table, $conflicts);
 }