Skip to content

Instantly share code, notes, and snippets.

@rightfold
Created March 2, 2014 14:24
Show Gist options
  • Save rightfold/1a1666f727ee8259213f to your computer and use it in GitHub Desktop.
Save rightfold/1a1666f727ee8259213f to your computer and use it in GitHub Desktop.
<?php
namespace FHP\Read;
class InvalidTokenException extends \Exception { }
class _EndOfTextException extends \Exception { }
function _chars($text) {
while ($text !== false) {
yield $text[0];
$text = substr($text, 1);
}
throw new _EndOfTextException();
}
function _is_whitespace($c) {
return strpos(" \n,", $c) !== false;
}
function _is_identifier_start($c) {
return ($c >= 'a' && $c <= 'z')
|| ($c >= 'A' && $c <= 'Z')
|| strpos("+-*/&|^!<>=?", $c) !== false;
}
function _is_identifier_rest($c) {
return _is_identifier_start($c)
|| ($c >= '0' && $c <= '9');
}
function read($text) {
$tokens = lex($text . "\n");
foreach ($tokens as $token) {
var_dump($token);
}
}
function lex($text) {
try {
$chars = _chars($text);
loop:
while (_is_whitespace($chars->current())) {
$chars->next();
}
if (_is_identifier_start($chars->current())) {
$identifier = '';
do {
$identifier .= $chars->current();
$chars->next();
} while (_is_identifier_rest($chars->current()));
yield (object)['token' => 'identifier', 'value' => $identifier];
goto loop;
}
if ($chars->current() === '"') {
$string = '';
for (;;) {
$chars->next();
if ($chars->current() === '"') {
break;
} else {
$string .= $chars->current();
}
}
yield (object)['token' => 'string', 'value' => $string];
goto next;
}
switch ($chars->current()) {
case '(': yield (object)['token' => 'lparen']; goto next;
case ')': yield (object)['token' => 'rparen']; goto next;
}
throw new InvalidTokenException();
next:
$chars->next();
goto loop;
} catch (_EndOfTextException $e) {
yield (object)['token' => 'eof'];
}
}
read('(echo "Hello, world!")');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment