/** * Creates a new collection of rules. * * You must provide a list of rules, the following formats are accepted: * * #### Rules as arrays * * ``php * [ * 'S -> a A' => function (&$info) { }, * 'A -> b B' => function (&$info) { }, * 'B -> c', // semantic routine is optional * .... * ] * ``` * * #### Rules as a single string * * In this case no semantic routine is given for each rule * * ```php * [ * 'S -> a A', * 'A -> b B', * 'C -> c', * ] * ``` * * #### Rules as a rule objects * * ```php * [ * new Rule('S -> a A', function (&$info) { }), * new Rule('A -> b B', function (&$info) { }), * new Rule('B -> c'), // semantic routine is optional * ] * ``` * * --- * * Of course you can combine formats: * * ```php * [ * 'S -> a A' => function($info) { }, * 'A -> b B', * new Rule('B -> c'), * ] * ``` * * @param array $collection List of rules given as an array * @return void */ public function __construct(array $collection = []) { if (empty($collection)) { return; } $i = 0; foreach ($collection as $index => $rule) { if (!$rule instanceof Rule) { if (is_string($index) && is_callable($rule)) { // 'S -> a' => function() $left = $index; $right = $rule; } elseif (is_integer($index) && is_string($rule)) { // 0 => 'S -> a' $left = $rule; $right = ''; } if (isset($left) && isset($right)) { $rule = new Rule($left, $right); unset($left, $right); } } if (!$rule instanceof Rule) { continue; } array_unshift($this->_variables, $rule->lhs()); if ($i == 0) { $this->_startVariable = $rule->lhs(); } $this->_rules[] = $rule; $i++; } $this->_variables = array_unique($this->_variables); foreach ($this->_rules as $rule) { $rhs = $rule->rhs(); $rhs = explode(' ', $rhs); $rhs = array_diff($rhs, $this->_variables); $this->_terminals = array_merge($this->_terminals, $rhs); } $this->_terminals = array_unique($this->_terminals); }