From b7388cdc04ee6385fea7cd5e6e2fdc57b1845624 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Wed, 30 Oct 2024 19:05:32 +0900 Subject: Add slides --- src/.editorconfig | 5 + src/a.php | 13 +++ src/b.php | 286 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 304 insertions(+) create mode 100644 src/.editorconfig create mode 100644 src/a.php create mode 100644 src/b.php (limited to 'src') diff --git a/src/.editorconfig b/src/.editorconfig new file mode 100644 index 0000000..819fb4e --- /dev/null +++ b/src/.editorconfig @@ -0,0 +1,5 @@ +root = true + +[*.php] +indent_style = space +indent_size = 4 diff --git a/src/a.php b/src/a.php new file mode 100644 index 0000000..1003341 --- /dev/null +++ b/src/a.php @@ -0,0 +1,13 @@ + Word::Echo_, + 'for' => Word::For_, + 'if' => Word::If_, + 'elseif' => Word::ElseIf_, + 'else' => Word::Else_, + }; + $i = $j; + } else if ($first === '$') { + $i += 1; + $j = $i; + while (ctype_alpha($input[$j])) { + $j += 1; + } + $result[] = new Variable(substr($input, $i, $j - $i)); + $i = $j; + } else if ($first === '"') { + $i += 1; + $j = $i; + $s = ''; + while ($input[$j] !== '"') { + if ($input[$j] === '\\') { + $j += 1; + if ($input[$j] === 'n') { + $s .= "\n"; + } else { + $s .= $input[$j]; + } + } else { + $s .= $input[$j]; + } + $j += 1; + } + $result[] = $s; + $i = $j + 1; + } + } + + return $result; +} + +class Php { + private array $words; + private int $position; + private array $variables; + + public function __construct(array $words) { + $this->words = $words; + $this->position = 0; + $this->variables = []; + } + + public function runPhp(): void { + $this->expectWord(Word::PhpTag); + $this->runStatements(); + } + + private function runStatements(bool $doRun = true): void { + while (true) { + $first = $this->words[$this->position] ?? null; + if ($first === Word::For_) { + $this->runForStatement($doRun); + } else if ($first === Word::If_) { + $this->runIfStatement($doRun); + } else if ($first === Word::Echo_) { + $this->runEchoStatement($doRun); + } else { + break; + } + } + } + + private function runForStatement(bool $doRun = true): void { + $this->position += 1; // skip 'for' + $this->expectWord(Word::LeftParen); + $this->calculateExpression($doRun); + $this->expectWord(Word::Semicolon); + $condition_position = $this->position; + while (true) { + $condition_result = $this->calculateExpression($doRun); + $this->expectWord(Word::Semicolon); + $update_position = $this->position; + if (!$condition_result) { + $this->skipExpression(); + $this->expectWord(Word::RightParen); + $this->expectWord(Word::LeftBrace); + $this->skipProgram(); + $this->expectWord(Word::RightBrace); + break; + } + $this->skipExpression(); + $this->expectWord(Word::RightParen); + $this->expectWord(Word::LeftBrace); + $this->runStatements($doRun); + $this->expectWord(Word::RightBrace); + $this->position = $update_position; + $this->calculateExpression($doRun); + $this->position = $condition_position; + } + } + + private function runIfStatement(bool $doRun = true): void { + $this->position += 1; // skip 'if' or 'elseif' + $this->expectWord(Word::LeftParen); + $condition = $this->calculateExpression($doRun); + $this->expectWord(Word::RightParen); + $this->expectWord(Word::LeftBrace); + $this->runStatements($doRun && $condition); + $this->expectWord(Word::RightBrace); + $next_word = $this->words[$this->position] ?? null; + if ($next_word === Word::ElseIf_) { + $this->runIfStatement($doRun && !$condition); + } else if ($next_word === Word::Else_) { + $this->position += 1; // skip 'else' + $this->expectWord(Word::LeftBrace); + $this->runStatements($doRun && !$condition); + $this->expectWord(Word::RightBrace); + } + } + + private function runEchoStatement(bool $doRun = true): void { + $this->position += 1; // skip 'echo' + $value = $this->calculateExpression($doRun); + if ($doRun) { + echo $value; + } + $this->expectWord(Word::Semicolon); + } + + private function calculateExpression(bool $doRun = true): int|string|bool|null { + $left_hand_side = $this->getNextWord(); + while (true) { + $next_word = $this->words[$this->position]; + if ($next_word === Word::Assign) { + $this->position += 1; // skip '=' + $right_hand_side = $this->getNextWord(); + if ($doRun) { + assert($left_hand_side instanceof Variable); + $left_hand_side = $this->variables[$left_hand_side->name] = $right_hand_side; + } + } else if ($next_word === Word::LessThan) { + $this->position += 1; // skip '<=' + $right_hand_side = $this->getNextWord(); + $left_hand_side = $this->convertWordToValue($left_hand_side) <= $this->convertWordToValue($right_hand_side); + } else if ($next_word === Word::StrictlyEqual) { + $this->position += 1; // skip '===' + $right_hand_side = $this->getNextWord(); + $left_hand_side = $this->convertWordToValue($left_hand_side) === $this->convertWordToValue($right_hand_side); + } else if ($next_word === Word::Modulo) { + $this->position += 1; // skip '%' + $right_hand_side = $this->getNextWord(); + $left_hand_side = $this->convertWordToValue($left_hand_side) % $this->convertWordToValue($right_hand_side); + } else if ($next_word === Word::Increment) { + $this->position += 1; // skip '++' + if ($doRun) { + $left_hand_side = $this->variables[$left_hand_side->name] = $this->variables[$left_hand_side->name] + 1; + } + } else { + return $this->convertWordToValue($left_hand_side); + } + } + } + + private function getNextWord(): int|string|Variable { + $word = $this->words[$this->position]; + $this->position += 1; + return $word; + } + + private function convertWordToValue(int|string|bool|Variable $word): int|string|bool|null { + if ($word instanceof Variable) { + return $this->variables[$word->name]; + } else { + return $word; + } + } + + private function skipExpression(): void { + $this->calculateExpression(doRun: false); + } + + private function skipProgram(): void { + $this->runStatements(doRun: false); + } + + private function expectWord(Word $expected_word): void { + if ($this->words[$this->position] !== $expected_word) { + throw new RuntimeException("Expected $expected_word at position $this->position"); + } + $this->position += 1; + } +} + +$input = file_get_contents('./a.php'); +$words = split_into_words($input); + +$php = new Php($words); +$php->runPhp(); -- cgit v1.2.3-70-g09d2