LINUX.ORG.RU

[C++]парсер матем. выражений

 


0

1

Уважаемые,
возник такой вопрос: есть ли на С++ парсер несложных математических выражений. На пример "({1}*{2})-sin({3})/4", где в {} указан номер элемента массива.
Массив я получаю в ходе выполнения программы, а выражение задается пользователем. Выражения содержат самое необходимое (+ - / * sin() cos() и пр, что есть с стандартной мат библиотеке для С++).
Если такая штука есть под Qt - вообще супер.

можно например транслировать нехитрыми заменами твое выражение в ecma и запускать через скриптовый движок в qt ^_^

trashymichael ★★★
()

Могу залить куда-нибудь вечером свою поделку 6-летней давности: всего один классец, работает стабильно и шустро, поддерживает переменные, константы, сокращенную запись умножения

mannaz
()
Ответ на: комментарий от mannaz

Могу залить куда-нибудь вечером свою поделку 6-летней давности: всего один классец, работает стабильно и шустро, поддерживает переменные, константы, сокращенную запись умножения

если не сложно - spike@me.by

spike_by
() автор топика

У Страуструпа где-то в первых главах калькулятор с таким парсером приведен в качестве примера. Можно прямо из книжки скопипастить.

ddos3
()
Ответ на: комментарий от Love5an

> это руками пишется за полчаса

Ну только если предварительно код наизусть выучить, а потом по памяти набирать ;)

archimag ★★★
()
Ответ на: комментарий от archimag

Можно у Страуструпа списать. У него как раз в примерах и был калькулятор с четырьмя простейшими действиями. Добавить еще функций будет несложно.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Reset

> на flex+bison такое пишется за 10 минут

Может сделаете скринкаст (ведь всего 10 минту, это как сходить покурить)? Уж очень хочется понаблюдать за работой мастера...

archimag ★★★
()
Ответ на: комментарий от archimag

наверное, лучше самому, «посоветовавшись» со Страуструпом)

spike_by
() автор топика
Ответ на: комментарий от archimag

попробовал, как раз 10 минут уходит на написание и тестирование двух файлов (.l, .y), если делать к этому хозяйству интерфейс, то будет чуть дольше

Reset ★★★★★
()
Ответ на: комментарий от Love5an

>да простой recursive-descent парсер написать, там нефиг делать же

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

dmitry_vk ★★★
()
Ответ на: комментарий от jtootf

>а если тебе нужен простой наколенный парсер, то он пишется за пару часов

Начитанным плюсистом нормальный наколенный парсер пишется ещё быстрее, ибо разобран в Страуструпе =)

yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

> Начитанным плюсистом нормальный наколенный парсер пишется ещё

быстрее, ибо разобран в Страуструпе =)


У Страуструпа не совсем то. Во-первых, там нет поддержки функций, а для их добавления нужно существенно переработать и усложнить код. Во-вторых, там и делается не совсем то, ибо расчёт ведётся немедленно, по ходу разбора выражений, а автору надо, скорей всего, сохранять выражение в виде некоего объекта, который потом можно будет многократно вызывать с разными наборами данных, а это тоже проблема несколько другого уровня.

archimag ★★★
()
Ответ на: комментарий от gizzka

boost::spirit же.

Да ну вас, извращенцев:)

+1 к связке flex+bison

V_L_A_D ★★
()
Ответ на: комментарий от trashymichael

а еще лучше сделать нужных биндингов и просто кормить формулу скрипту, заменив {X} индексы на индексы конкрентного объекта, передаваемого в скрипт.

trashymichael ★★★
()
Ответ на: комментарий от trashymichael

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

spike_by
() автор топика
Ответ на: комментарий от yoghurt

Начитанным плюсистом нормальный наколенный парсер пишется ещё быстрее, ибо разобран в Страуструпе =)

быстрее он пишется только в том случае, если этот самый плюсист по роду деятельности регулярно пишет парсеры (либо только что прочитал этот раздел в Страуструпе)

jtootf ★★★★★
()
Ответ на: комментарий от jtootf

пока остановился на решении такого рода
«{1}+{2}» заменяется цифрами и получаю типа

 QScriptEngine myEngine;
 QScriptValue three = myEngine.evaluate("28 + 43");

Только вопрос: понимает ли QScriptEngine.evaluate("") функции типа abs(-4*3)?
Похоже, не понимает. Надеюсь, что я не прав)))

spike_by
() автор топика
Ответ на: комментарий от spike_by

чего-то ты мудришь

parser.y

%{
#include <stdio.h>
double * array;
extern char * yytext;
#define YYSTYPE double
%}
%token NUMBER
%left '+' '-'
%left '*'
%%
body:  expr '\n' { fprintf(stderr, "%lf\n", $1); }
        | body expr '\n' { fprintf(stderr, "%lf\n", $2); }
        ;

expr: NUMBER { $$ = $1; }
        | '-' expr { $$ = -$2; }
        | expr '*' expr { $$ = $1 * $3; }
        | expr '+' expr { $$ = $1 + $3; }
        | expr '-' expr { $$ = $1 - $3; }
        | '(' expr ')' { $$ = $2; }
        | '{' NUMBER '}' { $$ = array[(int)($2)];}
        ;
%%

int yyerror(const char * a)
{
        return 0;
}

int yywrap()
{
        return 1;
}

int main()
{
        double ff[] = {1,2,3,4,5,6};
        array = &ff[0];
        while (yyparse());
}

scanner.l

%{
#define NUMBER 258
extern double yylval;
%}
%%
"\n" { return '\n'; }
[0-9]*\.?[0-9]+ { yylval = atof(yytext); return NUMBER; }
. { return yytext[0]; }
%%

добавить поддержку функций и интерфейс тебе домашнее задание

Reset ★★★★★
()
Ответ на: комментарий от Reset

> добавить поддержку функций

Без поддержки функций совсем не спортивно, ибо решение без них есть у Страуструпа и добавить функций заметно увеличивает сложность.

И я не понял, оно что, будет парсить каждый раз, когда необходимо что-нибудь вычислить? Это очень плохо. Парсить надо только один раз и сохранять результат в объекте, который можно использовать многократно с разными данными.

archimag ★★★
()
Ответ на: комментарий от Reset

добавить поддержку функций и интерфейс тебе домашнее задание

Прошу извинить за глупый вопрос - Ваш код на С++?

spike_by
() автор топика
Ответ на: комментарий от archimag

> Без поддержки функций совсем не спортивно

это делается тривиально — все функции задаем в .l и соответственно в .y их ловим и вызываем

И я не понял, оно что, будет парсить каждый раз, когда необходимо что-нибудь вычислить?

такой задачи не стояло, но никто не запрещает генерить этот объект внутри .y

Reset ★★★★★
()
Ответ на: комментарий от spike_by

Мой код генерирует код на С. Если .y переименовать в .ypp, то будет генерироваться код на C++.

Советую таки осилить flex и bison, на них потом очень быстро делаются многие вещи.

Reset ★★★★★
()
Ответ на: комментарий от mumg

> выражение задается пользователем

НИКТО не упомянул про обратную польскую запись


Чувак, на дворе уже как бы даже не девяностые

mannaz
()
Ответ на: комментарий от mumg

> так сейчас и алгебра другая?

Нет, алгебра не изменилась, а вот СССР больше нет. ABBA распались, Саддама повесили.

mannaz
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.