парсинг математических выражений - PullRequest
10 голосов
/ 28 мая 2010

(в c90) (linux)

ввод:

sqrt(2 - sin(3*A/B)^2.5) + 0.5*(C*~(D) + 3.11 +B)
a
b   /*there are values for a,b,c,d */
c
d

вход:

cos(2 - asin(3*A/B)^2.5) +cos(0.5*(C*~(D)) + 3.11 +B)
a
b   /*there are values for a,b,c,d */
c
d

ввод:

sqrt(2 - sin(3*A/B)^2.5)/(0.5*(C*~(D)) + sin(3.11) +ln(B))
 /*max lenght of formula is 250 characters*/
a
b   /*there are values for a,b,c,d */
c   /*each variable with set of floating numbers*/
d

Как видно, формула инфикса во входных данных зависит от пользователя. Моя программа примет формулу и значение n-кортежей. Затем он вычисляет результаты для каждого значения a, b, c и d. Если вам интересно, я говорю, результат программы - график. / иногда, я думаю, что я возьму ввод и сохраню в строке. тогда возникает другая идея: «Я должен хранить формулу в структуре» но я не знаю, как я могу построить код на основе структуры. /

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

/* a,b,c,d is letters
 cos,sin,sqrt,ln is function*/

Ответы [ 5 ]

12 голосов
/ 28 мая 2010

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

После этого существует несколько способов оценки ввода. Один из самых простых способов сделать это - преобразовать выражение в постфикс с помощью алгоритма шунтирующий двор (оценка выражения с постфиксом - Easy с заглавной буквой E).

1 голос
/ 29 мая 2010

Возможно, самое простое, что можно сделать, это использовать встроенный язык, такой как Lua или Python, для которого оба языка написаны на C. К сожалению, если вы пойдете по маршруту Lua, вам придется преобразовать двоичные операции в вызовы функций , в этом случае, вероятно, проще использовать Python. Так что я пойду по этому пути.

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

Вот код Python, который вы можете использовать:

exec "import math;A=<vala>;B=<valb>;C=<valc>;D=<vald>;print <formula>".replace("^", "**").replace("log","math.log").replace("ln", "math.log").replace("sin","math.sin").replace("sqrt", "math.sqrt").replace("cos","math.cos")

Обратите внимание, что замены выполняются в Python, так как я уверен, что это проще сделать в Python, а не C. Также обратите внимание, что если вы хотите использовать xor ('^'), вам придется удалить .replace("^","**") и используйте ** для питания.

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

#include <Python.h>

int main(int argc, char* argv[])
{
  char* progstr = "...";
  Py_Initialize();
  PyRun_SimpleString(progstr);
  Py_Finalize();
  return 0;
}

Более подробную информацию о внедрении Python в C можно найти здесь: Расширение Python и документация по внедрению

Если вам нужно использовать результат вычисления в вашей программе, есть способы прочитать это значение из Python, но вам придется читать их самостоятельно.

1 голос
/ 29 мая 2010

Вы должны искать «абстрактные синтаксические деревья» и «деревья выражений», а также «лексический анализ», «синтаксис», «синтаксический анализ» и «теория компилятора». Чтение ввода текста и получение значения от него довольно сложно для большинства вещей (хотя мы часто пытаемся убедиться, что у нас есть простой ввод).

Первый шаг в создании синтаксического анализатора - записать грамматику для вашего языка ввода. В этом случае ваш язык ввода - это математические выражения, поэтому вы должны сделать что-то вроде:

expr => <function_identifier> ( stmt )
        ( stmt )
        <variable_identifier>
        <numerical_constant>

stmt => expr <operator> stmt

(я не писал такую ​​грамматику {ищите BNF и EBNF} в течение нескольких лет, так что я, вероятно, допустил несколько вопиющих ошибок, на которые кто-то другой любезно укажет) Это может быть намного сложнее в зависимости от того, как вы обрабатываете приоритет оператора (умножьте и определите устройство перед сложением и вычитанием содержимого типа), но смысл грамматики в этом случае - помочь вам написать синтаксический анализатор.

Существуют инструменты, которые помогут вам сделать это (yacc, bison, antlr и другие), но вы также можете сделать это вручную. Есть много способов сделать это, но у всех них есть одна общая черта - стек. Для обработки такого языка требуется нечто, называемое автоматом нажатия, что является просто причудливым способом сказать что-то, что может принимать решения на основе нового ввода, текущего состояния и верхнего элемента стека. Решения, которые он может принять, включают в себя нажатие, выталкивание, изменение состояния и объединение (превращение 2+3 в 5 является формой объединения). Объединение обычно называется производством, поскольку оно дает результат.

Из различных распространенных типов парсеров вы почти наверняка начнете с рекурсивного приличного парсера. Они обычно пишутся непосредственно на языке программирования общего назначения, таком как C. Этот тип синтаксического анализатора состоит из нескольких (часто многих) функций, которые вызывают друг друга, и в итоге они используют системный стек в качестве стека автоматов.

Еще одна вещь, которую вам нужно сделать, это записать различные типы слов и операторов, составляющих ваш язык. Эти слова и операторы называются лексемами и представляют собой токены вашего языка. Я представил эти жетоны в грамматике <like_this>, за исключением скобок, которые представляли себя.

Скорее всего, вы захотите описать свои лексемы с помощью набора регулярных выражений. Вы должны быть знакомы с ними, если вы используете grep, sed, awk или perl. Они представляют собой способ описания так называемого обычного языка, который может обрабатываться чем-то, что называется конечным автоматом. Это просто причудливый способ сказать, что это программа, которая может принимать решение об изменении состояния, рассматривая только его текущее состояние и следующий ввод (следующий символ ввода). Например, часть вашего лексического описания может быть:

[A-Z]   variable-identifier
sqrt    function-identifier
log     function-identifier
[0-9]+  unsigned-literal
+       operator
-       operator

Есть также инструменты, которые могут генерировать код для этого. lex, который является одним из них, тесно интегрирован с программой генерации синтаксического анализатора yacc, но поскольку вы пытаетесь учиться, вы также можете написать свой собственный код токенизатора / лексического анализа на языке C.

После того, как вы все это сделали (это, вероятно, займет у вас довольно много времени), вам понадобится, чтобы ваш синтаксический анализатор построил дерево для представления выражений и грамматики входных данных. В простом случае оценки выражений (например, при написании простой программы-калькулятора командной строки) ваш парсер может оценить формулу при обработке ввода, но для вашего случая, насколько я понимаю, вам нужно будет создать дерево (или Обратное польское представление, но деревья на мой взгляд проще).

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

0 голосов
/ 10 марта 2011

Проверьте этот пост: http://blog.barvinograd.com/2011/03/online-function-grapher-formula-parser-part-2/ Он использует библиотеку ANTLR для синтаксического анализа математических выражений, в этом специально используется вывод JavaScript, но ANTLR имеет много выходов, таких как Java, Ruby, C ++, C #, и вы должны иметь возможность использовать грамматику в посте для любого языка вывода.

0 голосов
/ 29 мая 2010

Кроме того, вы должны просмотреть свои сообщения в SO и другие сообщения, касающиеся бинарных деревьев. Реализуйте это, используя древовидную структуру. Траверс как инфикс для оценки. Были несколько отличных ответов на древовидные вопросы.

Если вам нужно сохранить это (для сохранения, как в файле), я предлагаю XML. Синтаксический анализ XML должен заставить вас по-настоящему оценить, насколько легко ваше назначение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...