/**
  * @inheritdoc
  */
 public function getRules()
 {
     $rules = new Rules();
     if (!array_key_exists('rules', $this->data)) {
         throw new ConfigurationException(".INI Configuration must contain 'rules' section.");
     }
     foreach ($this->data['rules'] as $patternStr => $probability) {
         $pattern = new RulePattern((int) $probability);
         $startToken = '';
         foreach (explode(' ', $patternStr) as $tokenStr) {
             if (strlen($tokenStr) <= 2) {
                 throw new ConfigurationException("Pattern {$patternStr}: Token {$tokenStr} must exceed 2 characters.");
             }
             $isStartToken = false;
             if ($tokenStr[0] === '<' && substr($tokenStr, -1) === '>') {
                 $isStartToken = true;
                 $tokenStr = substr($tokenStr, 1, -1);
                 $startToken = $tokenStr;
             }
             $token = new RulePatternToken($tokenStr, $isStartToken);
             $pattern->addToken($token);
         }
         if (empty($startToken)) {
             throw new ConfigurationException("Pattern {$patternStr}: Must contain start token.");
         }
         $rule = new Rule($startToken);
         $rule->addPattern($pattern);
         $rules->addRule($rule);
     }
     return $rules;
 }
 /**
  * @inheritdoc
  */
 public function getRules()
 {
     $data = $this->data;
     $rules = new Rules();
     foreach ($data->rule as $ruleData) {
         $rule = new Rule((string) $ruleData->token);
         $patternIdx = 0;
         foreach ($ruleData->patterns->pattern as $patternData) {
             $patternName = "Pattern {$rule->getTokenName()}#{$patternIdx}";
             $hasStartToken = false;
             $potentialStartTokenIdxs = [];
             $tokens = [];
             foreach ($patternData->token as $tokenData) {
                 $tokenName = (string) $tokenData;
                 $isStartToken = (bool) $tokenData['is_start_token'];
                 $tokens[] = ['name' => $tokenName, 'is_start_token' => $isStartToken];
                 if ($isStartToken) {
                     if ($tokenName !== $rule->getTokenName()) {
                         throw new ConfigurationException("{$patternName}: Only {$rule->getTokenName()} tokens can have the 'is_start_token' attribute.");
                     }
                     if ($hasStartToken) {
                         throw new ConfigurationException("{$patternName}: Multiple {$rule->getTokenName()} tokens with 'is_start_token' attribute found. Only one is allowed.");
                     } else {
                         $hasStartToken = true;
                     }
                 }
                 if ($tokenName === $rule->getTokenName()) {
                     $potentialStartTokenIdxs[] = count($tokens) - 1;
                 }
             }
             if (!$hasStartToken) {
                 if (count($potentialStartTokenIdxs) === 0) {
                     throw new ConfigurationException("Pattern {$rule->getTokenName()}/#{$patternIdx} must have unambiguous start token. No {$rule->getTokenName()} token found.");
                 } elseif (count($potentialStartTokenIdxs) > 1) {
                     throw new ConfigurationException("Pattern {$rule->getTokenName()}/#{$patternIdx} must have unambiguous start token. Multiple {$rule->getTokenName()} tokens found.");
                 } else {
                     $potentialStartTokenIdx = $potentialStartTokenIdxs[0];
                     $tokens[$potentialStartTokenIdx]['is_start_token'] = true;
                 }
             }
             $pattern = new RulePattern((int) $patternData['probability']);
             foreach ($tokens as $token) {
                 $pattern->addToken(new RulePatternToken($token['name'], $token['is_start_token']));
             }
             $rule->addPattern($pattern);
             $patternIdx++;
         }
         $rules->addRule($rule);
     }
     return $rules;
 }