Hoa central
Llk.php
Go to the documentation of this file.
1 <?php
2 
37 namespace Hoa\Compiler\Llk;
38 
39 use Hoa\Compiler;
40 use Hoa\Core;
41 use Hoa\Stream;
42 
56 class Llk
57 {
120  public static function load(Stream\IStream\In $stream)
121  {
122  $pp = $stream->readAll();
123 
124  if (empty($pp)) {
125  $message = 'The grammar is empty';
126 
127  if ($stream instanceof Stream\IStream\Pointable) {
128  if (0 < $stream->tell()) {
129  $message .=
130  ': the stream ' . $stream->getStreamName() .
131  ' is pointable and not rewinded, maybe it ' .
132  'could be the reason';
133  } else {
134  $message .=
135  ': nothing to read on the stream ' .
136  $stream->getStreamName();
137  }
138  }
139 
140  throw new Compiler\Exception($message . '.', 0);
141  }
142 
143  static::parsePP($pp, $tokens, $rawRules);
144 
145  $ruleAnalyzer = new Rule\Analyzer($tokens);
146  $rules = $ruleAnalyzer->analyzeRules($rawRules);
147 
148  return new Parser($tokens, $rules);
149  }
150 
160  public static function parsePP($pp, &$tokens, &$rules)
161  {
162  $lines = explode("\n", $pp);
163  $tokens = ['default' => []];
164  $rules = [];
165 
166  for ($i = 0, $m = count($lines); $i < $m; ++$i) {
167  $line = rtrim($lines[$i]);
168 
169  if (0 === strlen($line) || '//' == substr($line, 0, 2)) {
170  continue;
171  }
172 
173  if ('%' == $line[0]) {
174  if (0 !== preg_match('#^%skip\s+(?:([^:]+):)?([^\s]+)\s+(.*)$#u', $line, $matches)) {
175  if (empty($matches[1])) {
176  $matches[1] = 'default';
177  }
178 
179  if (!isset($tokens[$matches[1]])) {
180  $tokens[$matches[1]] = [];
181  }
182 
183  if (!isset($tokens[$matches[1]]['skip'])) {
184  $tokens[$matches[1]]['skip'] = $matches[3];
185  } else {
186  $tokens[$matches[1]]['skip'] =
187  '(?:' . $matches[3] . ')|' .
188  $tokens[$matches[1]]['skip'];
189  }
190  } elseif (0 !== preg_match('#^%token\s+(?:([^:]+):)?([^\s]+)\s+(.*?)(?:\s+->\s+(.*))?$#u', $line, $matches)) {
191  if (empty($matches[1])) {
192  $matches[1] = 'default';
193  }
194 
195  if (isset($matches[4]) && !empty($matches[4])) {
196  $matches[2] = $matches[2] . ':' . $matches[4];
197  }
198 
199  if (!isset($tokens[$matches[1]])) {
200  $tokens[$matches[1]] = [];
201  }
202 
203  $tokens[$matches[1]][$matches[2]] = $matches[3];
204  } else {
205  throw new Compiler\Exception(
206  'Unrecognized instructions:' . "\n" .
207  ' %s' . "\n" . 'in file %s at line %d.',
208  1,
209  [
210  $line,
211  $stream->getStreamName(),
212  $i + 1
213  ]
214  );
215  }
216 
217  continue;
218  }
219 
220  $ruleName = substr($line, 0, -1);
221  $rule = null;
222  ++$i;
223 
224  while ($i < $m &&
225  isset($lines[$i][0]) &&
226  (' ' === $lines[$i][0] ||
227  "\t" === $lines[$i][0] ||
228  '//' === substr($lines[$i], 0, 2))) {
229  if ('//' === substr($lines[$i], 0, 2)) {
230  ++$i;
231 
232  continue;
233  }
234 
235  $rule .= ' ' . trim($lines[$i++]);
236  }
237 
238  if (isset($lines[$i][0])) {
239  --$i;
240  }
241 
242  $rules[$ruleName] = $rule;
243  }
244 
245  return;
246  }
247 }
248 
252 Core\Consistency::flexEntity('Hoa\Compiler\Llk\Llk');
static parsePP($pp, &$tokens, &$rules)
Definition: Llk.php:160
static load(Stream\IStream\In $stream)
Definition: Llk.php:120