public function run() { $this->variables = []; $token = $this->scanner->next(TRUE); $stack = new Stack(); $stack->push('$'); do { $a = $stack->topTerminal(); try { switch ($this->getFromTable($a, $token)) { case '=': debug::printString(debug::TYPE_PRECEDENCE, "= so push token"); $stack->push($token); $token = $this->scanner->next(TRUE); break; case '<': debug::printString(debug::TYPE_PRECEDENCE, "< so push < and token"); $stack->pushTerminal('<'); $stack->push($token); $token = $this->scanner->next(TRUE); break; case '>': // Hledáme pravidlo! $found = FALSE; foreach ($this->rules as $key => $rule) { $error = FALSE; for ($i = 0; $i < count($rule['source']); $i++) { $tmp = $stack->top($i); if (is_array($tmp) && !isset($tmp['nonTerminal'])) { $tmp = $this->normalizeCodes($tmp); } if (is_array($tmp) && $tmp['nonTerminal'] != $rule['source'][count($rule['source']) - 1 - $i] || !is_array($tmp) && $tmp != $rule['source'][count($rule['source']) - 1 - $i]) { $error = TRUE; $i = count($rule['source']); } } $error = $error || $stack->top(count($rule['source'])) != '<'; if (!$error) { $result = []; foreach ($rule['source'] as $unused) { $result[] = $stack->pop(); } $stack->pop(); $stack->push(['nonTerminal' => $rule['target'], 'terminals' => $result]); $found = TRUE; break; } } if (!$found) { $stack->debug(); throw new PrecedenceException("Error - rule not found! " . print_r($token, TRUE) . " " . print_r($a, TRUE)); } else { debug::printString(debug::TYPE_PRECEDENCE, "rule: " . $key . " " . $rule['target'] . " -> " . implode(' ', $rule['source'])); } break; case '#': if ($a == '$' && in_array($token['code'], $this->stopTokens)) { $this->scanner->back(); $token = ['code' => T_SEMICOLON, 'value' => ';']; } else { throw new PrecedenceException(print_r($a, TRUE) . print_r($token, TRUE)); } break; default: die("Chyba v precedenční tabulce"); } // This solve function calls with any argument number try { $e1 = $stack->top(); $comma = $stack->top(1); $e2 = $stack->top(2); if (isset($e1['nonTerminal']) && $e1['nonTerminal'] == 'E' && isset($comma['code']) && $comma['code'] == T_COMMA && isset($e2['nonTerminal']) && $e2['nonTerminal'] == 'E') { $stack->pop(); $stack->pop(); $stack->pop(); $stack->push(['nonTerminal' => 'E', 'terminals' => [$e1, $comma, $e2]]); $stack->debug(); echo "\n"; } } catch (StackEmptyException $e) { } } catch (PrecedenceNotInTableException $e) { $this->scanner->back(); $token = ['code' => T_SEMICOLON, 'value' => ';']; } debug::printStack(debug::TYPE_PRECEDENCE, $stack); } while ($this->normalizeCodes($token) != '$' || $stack->topTerminal() != '$'); $this->result = $stack->top(); }