2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу 1, 2  След.
 
 Определение приоритетности операций
Сообщение12.09.2011, 14:52 


06/07/11
5
В строковой переменной находится уравнение($line="A=sqrt(B+C)+(D:E)"). Необходимо получить приоритетность операций в нем и записать в любую структуру данных(массив или прочее). Например, для уравнения выше:
1) B+C
2) D:E
3) sqrt(<Результат_Операции_1>)
4)<Результат_Операции_3>+<Результат_Операции_2>

Как то так. :?: Как это можно сделать?

 Профиль  
                  
 
 Re: Определение приоритетности операций
Сообщение12.09.2011, 15:00 
Заслуженный участник


09/08/09
3438
С.Петербург
Почитайте про преобразование инфиксного выражения в обратную польскую запись.

 Профиль  
                  
 
 Re: Определение приоритетности операций
Сообщение12.09.2011, 20:05 
Аватара пользователя


31/10/08
1244
Maslov
После прочтения выкинуть. И начать читать нормальные труды.

valeriim
Тебе нужен грамматический анализатор.
Для начало не плохо посмотреть, какие приоритеты у операций в разных языках программирования.
Также надо прочитать теорию про грамматический анализ.
Что не рекомендую читать, так это "Альфред Ахо,Рави Сети,Джеффри Ульман Компиляторы" также известная как книга дракона. Слишком за умно написано, совет больше пользоваться как справочником. А да термины придётся выучить, зачастую встречаются разные термины обозначающие одно и тоже.

Грамматический анализатор это разновидность парсера. Существует разные алгоритмы парсеров. Появились они в ходе развития теории языков. И каждый парсер может обрабатывать определённые разновидности языков.
В вашем случае я бы обратил внимание на рекурсивный парсер или на парсер на основе алгоритма магазинного автомата.
Первый легко реализовать самому, описав предварительно свод правил- грамматик. Второй тоже простой, но для посторониться требует знание теории.
Вот тут можно почерпнуть теорию.
http://www.intuit.ru/department/sa/comp ... dev_7.html
А да также в википедии все доходчиво расписано, правда в английской.
http://en.wikipedia.org/wiki/LR_parser

 Профиль  
                  
 
 Re: Определение приоритетности операций
Сообщение12.09.2011, 20:23 
Заслуженный участник


27/04/09
28128
Для таких выражений почему стандартный алгоритм преобразования из инфиксной записи с приоритетами и функциями не подходит? Очень даже подходит, и с грамматикой и составлением анализатора возиться не нужно — всё будет делать одна функция. М?

-- Пн сен 12, 2011 23:27:29 --

А, вы про магазинный автомат упомянули. Так он тут и нужен один! Ради такого случая возиться с грамматиками — странный способ улучшить себе жизнь.

 Профиль  
                  
 
 Re: Определение приоритетности операций
Сообщение12.09.2011, 20:56 
Аватара пользователя


31/10/08
1244
Цитата:
Для таких выражений почему стандартны
Для, каких таких?
Цитата:
записи с приоритетами и функциями не подходит?
Ну хотя бы тем что не поддерживает оператор"," - запятая. Не поддерживает унарные операции. Есть и другие недочёты.

 Профиль  
                  
 
 Re: Определение приоритетности операций
Сообщение12.09.2011, 21:23 
Заслуженный участник


09/08/09
3438
С.Петербург
Pavia в сообщении #482511 писал(а):
Maslov
После прочтения выкинуть. И начать читать нормальные труды.
Это Вы мне? Спасибо за совет, конечно, но я разные "труды" читал, в том числе, и "нормальные".

Тем не менее, на мой взгляд, прежде чем погружаться в теорию синтаксического анализа, перевода и компиляции и бросаться на борьбу с яками, бизонами и прочими парнокопытными, очень полезно реализовать простенький алгоритм разбора выражений ручками, пользуясь как раз таки стандартным способом построения обратной польской записи.

Pavia в сообщении #482526 писал(а):
Ну хотя бы тем что не поддерживает оператор"," - запятая.
Ну если автору во что бы то ни стало надо реализовать поддержку оператора ",", тогда конечно...

Pavia в сообщении #482526 писал(а):
Не поддерживает унарные операции.
Это Вы серьезно? :)
Очевидное расширение обратной польской записи на унарные, тернарные и операции с любым другим количеством операндов: при использовании знаков таких операций в вычислении выражения операция применяется к соответствующему числу последних встретившихся операндов.

 Профиль  
                  
 
 Re: Определение приоритетности операций
Сообщение12.09.2011, 21:33 
Заслуженный участник


27/04/09
28128
С первого раза не могу уяснить, что не так с запятой. Мешает правоассоциативность?

-- Вт сен 13, 2011 00:36:33 --

Да и вроде бы в алгоритме был способ учитывать правоассоциативность…

Или если имелась в виду польская запись — так ведь не обязательно её вычислять сразу же. Можно по ней построить дерево выражения, а потом его вычислять в соответствии с тем, какие операции/функции как хотят вычислять свои аргументы.

 Профиль  
                  
 
 Re: Определение приоритетности операций
Сообщение12.09.2011, 21:55 
Заслуженный участник


09/08/09
3438
С.Петербург
arseniiv в сообщении #482543 писал(а):
С первого раза не могу уяснить, что не так с запятой.
"Запятая" -- это не операция, а оператор. Если речь идет о реализации операторов (кроме простого оператора присваивания), то без полноценного синтаксического разбора, скорее всего, действительно не обойтись.

 Профиль  
                  
 
 Re: Определение приоритетности операций
Сообщение12.09.2011, 22:33 
Админ форума
Аватара пользователя


19/03/10
8952
Pavia в сообщении #482511 писал(а):
valeriim
Тебе нужен грамматический анализатор.
 !  Pavia, замечание за фамильярность. Читайте Правила форума:
Правила форума в http://dxdy.ru/post27356.html#p27356 писал(а):
1) Нарушением считается:

е) ..., фамильярность (у нас принято обращаться друг к другу на "Вы")...

 Профиль  
                  
 
 Re: Определение приоритетности операций
Сообщение13.09.2011, 20:52 
Заслуженный участник


27/04/09
28128
Maslov в сообщении #482551 писал(а):
"Запятая" -- это не операция, а оператор.
Ну это где как. :-) Но если, конечно, много операторов, тут целиком согласен, что нужна грамматика. А вообще, если автору и понадобятся операторы (даже в нужности ему запятой [ну, можно ведь её сделать точкой с запятой, чтобы не спуталась с разделителем параметров функции] я сомневаюсь), то можно их представить в виде функций if(switch-exp, true-exp, false-exp) — если потом переводить в дерево, как писал, то с управлением тем, что вычислять, а что нет, толк может быть! (Надеюсь, скобки не сильно затруднили чтение.)

А автор-то молчит!

 Профиль  
                  
 
 Re: Определение приоритетности операций
Сообщение20.09.2011, 05:29 
Заслуженный участник


26/07/09
1559
Алматы
2valeriim
В свое время, захотевши написать простой компилятор мат.выражений, но не будучи знакомым с теорией синтаксического анлиза, грамматического разбора и т.д., я "изобрел" простой парсер, специально для нужд разбора простых формул. Как потом оказалось, дизайн парсера оказался не таким уж и плохим. Фактически, это обычный рекурсивно-нисходящий парсер, но свернутый в одну функцию.

Выглядит он примерно так:
Код:
tree expr(int p)
{
    string op; tree left;
    if(p>maxp) return term();
    left=expr(p+1);
    if(!check(p, op)) return left;
    if(right(op))
        left=infix(p, op, left);
    else
        do left=infix(p+1, op, left) while(check(p, op));
    return left;
}
}


Здесь p обозначает приоритет оператора (начиная с нуля); maxp -- соответсвенно максимално возможный приоритет; функция check принимает приоритет и ссылку на буфер, проверяет является ли текущая лексема оператором и если является, то совпадает ли его приоритет с данным, потом копирует оператор в указанный буфер и считывает следующую лексему (в случае удачи) и возвращает результат проверки; фукция infix, как нетрудно догадаться, обрабатывает бинарный оператор указанного приоритета, т.е. конструирует соответствующий узел дерева; функция term обрабатывает скобки и унарные (префиксные/постфиксные операторы); ну и наконец, функция right просто проверяет оператор на правую ассоциативность.

Как может выглядеть код для infix(p, op, left)? Он должен создать новый узел с меткой op, левой подветкой которого станет переданная ветка, а правая ветка будет получена вызовом expr(p). Возможный вид infix'а:
Код:
tree infix(int p, char *op, tree left)
{
    return mknode(op, left, expr(p));
}


Функция term очень проста, но места занимает очень много. Начать её писать можно так:
Код:
tree term()
{
    if(match("("))
    {
        t=expr(0);
        expect(")");
        return t;
    }
    switch(token.kind)
    {
        case tk_number: t=mknode(token.value); next_token(); return t;
            ...

Функция match проверяет, совпадает ли текст текущей лексемы с данным и если совпадает, то считывает следующую лексему и возвращает истину. Функция expect проводит почти такую-же проверку, но при несовпадении генерирует ошибку (и если парсер допускает восстановление после ошибок, то expect может считывать новую лексему в любом случае). Что означает next_token() надеюсь понятно (да, ещё и лексический анализатор придется написать, например в виде конечного автомата).

В общем, как-то так. Это проверенная работающая схема. Осталось только правильно распечатать построенное синтаксическое дерево; собственно в этом задание-то и заключалось. Наверное код будет примерно таким:
Код:
display(tree AST)
{
    switch(AST->node_kind)
    {
        nk_op:
            display(AST->left);
            display(AST->right);

            display(AST->left)
            print(AST->op);
            display(ASR->right);
            break;

        nk_funccall:
            for(i=0; i<AST->argc; i++) display(AST->argv[i]);
            print(AST->id);
            print("(");
            for(i=0; i<AST->argc; i++)
            {
                if(i) print(", ");
                display(AST->argv[i]);
            }
            print(")");

                ...

Точно не знаю, как он должен выглядет, но, думаю, достаточно немного поэкспериментировать, чтобы это понять.

Подход с построением синтаксического дерева оправдан за счет необходимости дублировать выводимые на печать операнды при печати объемлющего их выражения. Т.е. в выражении (a+b)*(c+d) сначала печатаем (a+b), потом (c+d), а потом все выражение, т.е. содержимое скобок печатается по нескольку раз. Навреное уж лучше один раз построить дерево, чем хранить все промежуточные куски строк (хотя ведь достаточно хранить позиции и длины подстрок, но генерация дерева хороша в образовательном смысле :) ).

P.S.: Я считаю, что для таких заданий прекрасно подходит техника синтаксического разбора с использованием комбинаторов парсеров, вроде хаскелевского parsec'а, boost::spirit для C++, или даже reparse для js. Это наиболее красивый способ дословного перевода нфбн-грамматики в программный код парсера. Обычно к таким библиотекам неизменно прилагается пример реализации калькулятора, вот его то и нужно переделать для генерации синтаксического дерева, которое потом нужно будет правильно распечатать, см. выше.

P.P.S.: Насчет запятой и правоассоциативности ничего не понял. Чем запятая отличается от других операторов? И при чем тут правоассоциативность(с каких пор запятая правоассоциативна)? И что особого в правой ассоциативности? Обычно, при прямом построении рекурсивно-нисходящего парсера, могут возникать проблемы, но не для право-, а для левоассоциативных операций (функция сразу же вызывает саму себя рекурсивно, что приводит к зацикливанию); правда это никакая не проблема и все исправляется простыми циклами...

 Профиль  
                  
 
 Re: Определение приоритетности операций
Сообщение20.09.2011, 16:22 
Заслуженный участник


27/04/09
28128
Хм, и правда, она и левоассоциативно неплохо смотрится. Что-то, может, упущено?

(Более точное исследование)

Пусть у нас имеется некая стековая машина. Тогда a, b транслируется в
Код:
a; drop; b;
Далее, (a, b), c:
Код:
a; drop; b; drop; c;
Напротив, a, (b, c):
Код:
a; drop; b; drop; c;

Хм, действительно, разницы никакой нет, и я всё спутал. Или же мы с Circiterом что-то недоучли. В любом случае, я не выгирываю. :lol:

 Профиль  
                  
 
 Re: Определение приоритетности операций
Сообщение20.09.2011, 19:51 
Заслуженный участник


26/07/09
1559
Алматы
2arseniiv
Семантика оператора может быть любой. Я всего-лишь ссылался мысленно на запятую в C. :) Там она левоассоциативна: a, b, c = (a, b), c. Хотя да, небольшая путаница есть; ведь с учетом семантики возврата оператором запятая значения второго операнда можно было бы считать её, запятую, ассоциативной справа. Правда в последнем случае, с учетом свободы компилятора вычислять аргументы функций в произвольном порядке, возникли бы проблемы с видимостью уже полученных в более левых вычислениях результатов для более правых вычислений: в a, f(a) второй операнд должен гарантированно иметь доступ к первому, уже посчитанному, но не наоборот. Хороший пример правоассоциативного оператора -- равенство; ассоциативность справа дает возможность писать w=x=y=z=0, и этого уже не отнимешь. Да, я считаю систему приоритетов и ассоциативностей операторов C/C++ хорошо продуманной и достаточно удачной.

 Профиль  
                  
 
 Re: Определение приоритетности операций
Сообщение20.09.2011, 22:23 
Заслуженный участник


27/04/09
28128
Circiter в сообщении #484600 писал(а):
Я всего-лишь ссылался мысленно на запятую в C. :) Там она левоассоциативна: a, b, c = (a, b), c.
Я тоже на него. Почему-то думал, что они в одной группе с присваиваниями. :oops:

 Профиль  
                  
 
 Re: Определение приоритетности операций
Сообщение22.09.2011, 23:24 


17/05/11
158
Pavia в сообщении #482511 писал(а):
Maslov
какие приоритеты у операций в разных языках программирования.


что, где то сложение может быть выше умножения? :shock:

что за бред. приоритет везде един

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 16 ]  На страницу 1, 2  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group