Initial commit

This commit is contained in:
2020-05-08 00:37:29 +02:00
commit e2b8f1d7aa
29 changed files with 1497 additions and 0 deletions

23
src/Program/Block.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
namespace Program;
class Block
{
public string $N;
/** @var Word[] */
public array $words;
public function __construct(string $N)
{
$this->N = $N;
$this->words = [];
}
public function addWord(Word $word): void
{
$this->words[] = $word;
}
}

38
src/Program/Program.php Normal file
View File

@@ -0,0 +1,38 @@
<?php
namespace Program;
use ArrayIterator;
use IteratorAggregate;
use Traversable;
class Program implements IteratorAggregate
{
public int $N;
/** @var Block[] */
private array $blocks;
public function __construct(int $N)
{
$this->N = $N;
$this->blocks = [];
}
public function addBlock(Block $block): self
{
$this->blocks[] = $block;
return $this;
}
/**
* @return ArrayIterator|Traversable|Block[]
*/
public function getIterator()
{
return new ArrayIterator($this->blocks);
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace Program;
use RuntimeException;
class ProgramParser
{
public function parseFile(string $filename): Program
{
$lines = explode(PHP_EOL, file_get_contents($filename));
$lines = array_filter($lines);
return $this->parse($lines);
}
public function parse(array $lines): Program
{
// In the first parsing stage, all words are parsed from the file.
/** @var Word[] $words */
$words = [];
foreach ($lines as $line) {
$characters = str_split(trim($line) . ' ');
$state = 'NONE';
$wordBuffer = [];
foreach ($characters as $character) {
if ('READING' === $state) {
if ('-' === $character || is_numeric($character)) {
$wordBuffer['value'] .= $character;
continue;
}
// Word is finished
$words[] = new Word($wordBuffer['register'], $wordBuffer['value']);
$wordBuffer = [];
$state = 'NONE';
continue;
}
if ('NONE' === $state && ctype_alpha($character)) {
$state = 'READING';
$wordBuffer = ['register' => $character, 'value' => ''];
continue;
}
if (stripos($line, 'EOF') !== false) {
break 2; // End of program reached
}
if (';' === $character) {
break; // Rest of line is a comment
}
}
}
// In the second stage, the words are ordered by N numbers
// and shaped into a program
$firstWord = array_shift($words);
if (!preg_match('/^N9\d\d\d$/i', $firstWord)) {
throw new RuntimeException('Expected program number, got ' . $firstWord);
}
$program = new Program($firstWord->value);
$lineBuffer = null;
foreach ($words as $word) {
if ($word->register === 'N') {
if (!is_null($lineBuffer)) {
$program->addBlock($lineBuffer);
}
$lineBuffer = new Block($word->value);
continue;
}
$lineBuffer->addWord($word);
}
return $program;
}
}

28
src/Program/Word.php Normal file
View File

@@ -0,0 +1,28 @@
<?php
namespace Program;
class Word
{
public string $register;
public int $value;
public function __construct(string $register, int $value)
{
$this->register = $register;
$this->value = $value;
}
public function toString(): string
{
return "{$this->register}{$this->value}";
}
public function __toString()
{
return $this->toString();
}
}