Форум → Программирование → PHP для идиотов → Пишем интерпретатор логических выражений (для разгр. прав)
Пишем интерпретатор логических выражений (для разгр. прав)
Страницы: ← Предыдущая страница • Следующая страница →
-
-
29 сентября 2009 г. 19:40, спустя 1 час 58 минут 7 секунд
Теперь класс синтаксического анализа.
Он же и формирует строку для вычислителя.
Здесь используется немного доработанный класс лексического анализатора.
Переименовали его в lexer и имена лексем вынесли в константы (так их названия подхватывает "завершитель кода" в редакторе)class sintax{
/**
* Группы лексем, и соответствующие им коды операций
* <oper_1> ::= "+" | "-"
* <oper_2> ::= "*" | "/" | "%"
*
* @var array
*/
private $lexGroups = array(
'oper_1' => array(
lxPlus => '+',
lxMinus => '-' ),
'oper_2' => array(
lxAsterisk => '*',
lxDiv => '/',
lxMod => '%')
);
/**
* Объект вычислителя
* @var calc
*/
private $calc;
/**
* Конструктор
*/
public function __construct(){
$this->calc = new calc();
}
/**
* <operand> ::= <number> | "(" <expression_1> ")"
* // Это и следующее правило интегрировано в lexer
* <number> ::= <digit> { <digit> }
* <digit> ::= "0" | .. | "9"
*
* @param lex $lexer
*/
private function bnfOperand($lexer){
if(lxNumber == $lexer->type()){
$opn = 'c'.$lexer->value();
}elseif(lxBracketL == $lexer->type()){
$lexer->next();
$opn = $this->bnfExpr_1($lexer);
// дальше должна быть закрывающая скобка
if(lxBracketR != $lexer->type()){
throw new Exception('Ожидается lxBracketR');
}
}else{ // Ни числа ни скобки - исключение!
throw new Exception('Ожидается lxNumber или lxBracketL');
}
$lexer->next(); // переступаем через число или скобку … кто там был
return $opn;
}
/**
* <expr_3> ::= <operand>
* @param mixed $lexer
*/
private function bnfExpr_3($lexer){
return $this->bnfOperand($lexer);
}
/**
* <expr_2> ::= <expr_3> { <oper_2> <expr_3>}
* @param lexer $lexer
*/
private function bnfExpr_2($lexer){
$opn = $this->bnfExpr_3($lexer);
while(isset($this->lexGroups['oper_2'][$lexer->type()])){
$oper = 'p'.$this->lexGroups['oper_2'][$lexer->type()];
$lexer->next();
$tmp = $this->bnfExpr_3($lexer);
$opn .= ' '.$tmp.' '.$oper;
}
return $opn;
}
/**
* <expr_1> ::= <expr_2> { <oper_1> <expr_2>}
* @param lexer $lexer
*/
private function bnfExpr_1($lexer){
$opn = $this->bnfExpr_2($lexer);
while(isset($this->lexGroups['oper_1'][$lexer->type()])){
$oper = 'p'.$this->lexGroups['oper_1'][$lexer->type()];
$lexer->next();
$tmp = $this->bnfExpr_2($lexer);
$opn .= ' '.$tmp.' '.$oper;
}
return $opn;
}
/**
* Запуск вычисления выражения
*
* @param string $expression
* @return integer
*/
public function calculate($expression){
$lexer = new lexer($expression);
$opn = $this->bnfExpr_1($lexer);
if(lxEof != $lexer->type()){
throw new Exception('Выражение разобрано не до конца!');
}
// Это для демонстрашки. интересно же :)
echo "\n ОПН : \"$opn\"";
$result = $this->calc->calcString($opn);
return $result;
}
}Спустя 93 сек.Пример запуска:$str = '5 / 2 * (3 + 4) * 2';
$sintax = new sintax();
echo "<PRE>\n Выражение: $str";
$res = $sintax->calculate($str);
echo "\n Результат: $res</PRE>";
Ииии….. !!!!!
[tt] Выражение: 5 / 2 * (3 + 4) * 2
ОПН : "c5 c2 p/ c3 c4 p+ p* c2 p*"
Результат: 28
[/tt]
Черновой вариант готов. Работает. Теперь надо это всё обдумать … -
29 сентября 2009 г. 19:42, спустя 1 минуту 55 секунд
private $calc;
/**
* Конструктор
*/
public function __construct(){
$this->calc = new calc();
}
первое что бросилось в глаза…
почем у не так ?private $_calc = null;
public function init()
{
if (is_null($this->_calc)) {
$this->_calc = new calc;
}
return $this;
}
public function __construct(){
$this->init();
}Спустя 72 сек.про именование переменных и методов я опять молчу…. -
29 сентября 2009 г. 19:44, спустя 2 минуты 12 секунд
calc создается один раз при создании самого sintax и не удаляется. Нет надобности проверять, есть он или нет его. Но это так.
Код я совсем не вылизывал … пока добивался работоспособности. -
-
-
29 сентября 2009 г. 20:30, спустя 37 минут 18 секунд
Я в экстазе!
Добавляем унарные плюс и минус:
Подправляем БНФ правило<operand> ::= <oper_u> <operand> | <number> | "(" <expression_1> ")"
<oper_u> ::= "+" | "-"
Изменений в коде - фигня. Расширяем массив private $lexGroups - добавляем группу 'oper_u' с парой элементов и подправляем метод bnfOperand
…
}elseif(isset($this->lexGroups['oper_u'][$lexer->type()])){
$oper = $this->lexGroups['oper_u'][$lexer->type()];
$lexer->next();
$tmp = $this->bnfOperand($lexer);
$opn = $tmp.' '.'p'.$oper;
}elseif(lxBracketL == $lexer->type()){
…
И всё! Теперь мы и унарные операции знаем:
[tt] Выражение: 8 % 3 * -(3 + 4) * 2
ОПН : "c8 c3 p% c3 c4 p+ pu- p* c2 p*"
Результат: -28
[/tt] -
29 сентября 2009 г. 20:34, спустя 3 минуты 19 секунд
а зачем оно вобще нужно?
где применятеся на практике?
p.s. я смотрю, на пыхе все больше и больше миллионеров появляется)все умрут, а я изумруд -
29 сентября 2009 г. 20:39, спустя 5 минут 23 секунды
+1
а зачем оно вобще нужно?
где применятеся на практике?
p.s. я смотрю, на пыхе все больше и больше миллионеров появляется)Сапожник без сапог -
29 сентября 2009 г. 20:48, спустя 8 минут 57 секунд
Будет использоваться в "разграничении прав на уровне записи".
Выражением буде задано, имеет ли право юзер выполнять над данной записью (из какой-нить одной/нескольких таблиц) указанное действие. -
29 сентября 2009 г. 20:49, спустя 1 минуту 17 секунд
сложно-то все как, ладно
а я пойду дальше зарабатывать деньги :Dвсе умрут, а я изумруд -
-
30 сентября 2009 г. 21:16, спустя 21 час 7 минут 11 секунд
Волна_2 добавим макрооперации для удобной записи проверки бит.
Очень часто в выражениях нужно устраивать проверки (сразу же привожу классический вариант записи)
"все биты a,b,c в D подняты"
[tt] (D & (1<<a | 1<<b | 1<<c)) == (1<<a | 1<<b | 1<<c) [/tt]
"встречаются установленные биты среди битов a,b,c в D"
[tt] (D & (1<<a | 1<<b | 1<<c)) > 0[/tt]
Всё ещё страшнее, если a,b,c - выражения, а не константы.
Для более наглядной записи [tt](1<<a | 1<<b | 1<<c)[/tt] я придумал такой вариант [tt]{a,b,c..d,e}[/tt]
Прошу помочь с наглядным вариантом для записи проверки бит. Вместо
[tt]A & B == B[/tt] … ?
[tt]A & B != 0[/tt] … ?
и т.д. -
30 сентября 2009 г. 21:50, спустя 33 минуты 44 секунды
AndryG, на самом деле ты крут. эта хуйня никаму нахуй не надо. те кому она могла понадобится уже с ней разобрались и забыли. а ты сидишь и упорно ебешся. с одной стороны я не знаю битовых операций. нет я конечно знаю чо делают операторы над операндами но я не знаю где бы я сумел это применить даже если бы очень захотел. но ты! ты крут! ты расчехлишь битовые операции. обратную польскую нотацию. напишешь свойвелосыпедкалькулятор. и похвастаешся перед всеми своими знаниями. которые ты нигде не сможешь применить. но ты будешь знать. и будеш знать что применить их нельзя. и жызнь потеряет краски и ты впадешь в депресию и повесишся. и на могиле напишут что ты знал но никто не оценил.
пойди лучше чтото полезное выучи, регулярки что ли… -
30 сентября 2009 г. 21:56, спустя 6 минут 12 секунд
я сейчас ебусь с побитовыми операциями, уж не думал)))
но ничо, успешно :)Сапожник без сапог
Страницы: ← Предыдущая страница • Следующая страница →
Пожалуйста, авторизуйтесь, чтобы написать комментарий!