93 lines
No EOL
2.2 KiB
PHP
93 lines
No EOL
2.2 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Разбирвет строку запроса на токены
|
|
*/
|
|
class Lexer
|
|
{
|
|
const TOKEN_NOT = 1;
|
|
const TOKEN_OR = 2;
|
|
const TOKEN_LPAREN = 3;
|
|
const TOKEN_RPAREN = 4;
|
|
const TOKEN_AND = 5;
|
|
const TOKEN_WORD = 6;
|
|
const TOKEN_EOL = 7;
|
|
|
|
protected $src;
|
|
private $offset = 0;
|
|
public $token;
|
|
|
|
public function __construct ()
|
|
{
|
|
}
|
|
|
|
function setSource ($src)
|
|
{
|
|
$this->src = $src;
|
|
$this->offset;
|
|
}
|
|
|
|
private function skipSpace ()
|
|
{
|
|
while (!$this->isEOL() && $this->getChar() == " ") {
|
|
$this->offset++;
|
|
}
|
|
}
|
|
|
|
private function getChar ()
|
|
{
|
|
return $this->src [$this->offset];
|
|
}
|
|
|
|
/**
|
|
* Проверяет на конец строки
|
|
*/
|
|
private function isEOL () {
|
|
return $this->offset >= strlen($this->src);
|
|
}
|
|
|
|
/**
|
|
* Односимвольный токен
|
|
*/
|
|
private function easyToken () {
|
|
$ch = $this->getChar ();
|
|
switch ($ch) {
|
|
case '~': $token = array(self::TOKEN_NOT, $ch); break;
|
|
case '|': $token = array(self::TOKEN_OR, $ch); break;
|
|
case '(': $token = array(self::TOKEN_LPAREN, $ch); break;
|
|
case ')': $token = array(self::TOKEN_RPAREN, $ch); break;
|
|
case '&': $token = array(self::TOKEN_AND, $ch); break;
|
|
default:
|
|
$this->offset++;
|
|
$token = $this->getToken();
|
|
}
|
|
$this->offset++;
|
|
return $token;
|
|
}
|
|
|
|
/**
|
|
* Возвращает следующий токен
|
|
*/
|
|
public function getToken ()
|
|
{
|
|
$this->skipSpace ();
|
|
if ($this->isEOL()) {
|
|
return array(self::TOKEN_EOL, "");
|
|
}
|
|
if (ctype_alpha($this->getChar())) {
|
|
$start = $this->offset;
|
|
while (!$this->isEOL() && ctype_alpha($this->getChar())) {
|
|
$this->offset ++;
|
|
}
|
|
return array(self::TOKEN_WORD, substr ($this->src, $start, $this->offset-$start));
|
|
}
|
|
return $this->easyToken();
|
|
}
|
|
|
|
public function nextToken ()
|
|
{
|
|
$this->token = $this->getToken();
|
|
}
|
|
}
|
|
|
|
?>
|