Каков наилучший способ добавить поддержку формул и переменных в «Алгоритм маневровой площадки»?

#c #formula

#c #формула

Вопрос:

В настоящее время я работаю над этим проектом под названием «expression evaluator», и у меня есть несколько вопросов о том, как его кодировать.

Прежде всего, что делает этот «вычислитель выражений»? Он просто вычисляет вставленное вами выражение, оно должно поддерживать:

  • круглые круглые скобки
  • операторы: , -, /, *, <>, =, <=, >=, или, и, xor, не, мод,
  • все математические функции отсюда
  • вещественная, целочисленная и логическая константа (1, 1.1, -1, true, false и т. Д.)
  • обычные переменные, такие как var, например: 1 var // переменные можно использовать следующим образом: «var = 50 1 var», и он должен выводить 51.

В настоящее время мне удалось преобразовать строку в постфиксную нотацию (перевернутая польская нотация) и оценить ее, но в настоящее время она поддерживает только ( , -, *, /, ^) и только вещественные и целочисленные константы.

Как я мог бы добавить поддержку для остальных операторов / переменных / формул?

Я действительно пытался добавить поддержку переменных / формул, но это работает только для базовых выражений, таких как: pow (1, 3) 2, это выводит 3 (TRUE). Если я попробую более сложные выражения, это произойдет примерно так: pow (pow (2, 3), 2), это выводит 512, что неверно, оно должно выводить 64.

Вот мой код, чтобы вы могли проверить его самостоятельно.

 #include <algorithm>
#include <cmath>
#include <fstream>
#include <map>
#include <stack>
#include <string>
#include <vector>

#include <iostream>

// Setari
#define __DEBUG__ // Afiseaza informatii despre procesul de rezolvare.
#define __SUPPORT_DOUBLE__ // Activeaza suportul pentru numere reale.

// Variabile

std::vector<std::string> Infix;
std::stack<std::string> operators;
std::stack<std::string> Rezultat;

// Salvez operatorii si nivelul lor de prioritate intr-un dictioar pentru a face procesul de identificare mai rapid
std::map<std::string, short> Operators = { {" ", 1}, {"-", 1}, {"*", 2}, {"/", 2}, {"^", 3}, {"pow", 3}, {"==", 4}, {"=", 5} };

std::ifstream fin("eval.in");
std::ofstream fout("eval.out");


// Functii

// Caut in dictionarul 'Operators' operatorul si, daca-l gasesc returnez prioritatea acestuia.
int CheckOperator(const std::stringamp; op){
    const autoamp; it = Operators.find(op);

    if (it != Operators.end())
        return it->second;

    return 0;
}

int main(){
    std::string expr, token;
    while (std::getline(fin, token))
        expr.append(token);
    fin.close();
    
    // Analizez expresie si sterg caracterele inutile(  ).
    expr.erase(std::remove_if(expr.begin(), expr.end(), [](const charamp; c){ return c == '\'; }), expr.end());
    // Transform expresia in expresie postfix.
    
    for (size_t i = 0; i < expr.length();   i){
        char c = expr[i];
        token.clear();

        int prioritate = 0;
        
        token  = c;
        if (isdigit(c))
        {
            
            for (  i; i < expr.length();   i){
                c = expr[i];
#if defined(__SUPPORT_DOUBLE__)
                if (!isdigit(c) amp;amp; c != '.')
                    break;
#else
                if (!isdigit(c))
                    break;
#endif
                token  = c;
            }
            --i;
            Infix.push_back(token);
        }
        else if(isalpha(c))
        {
            for (  i; i < expr.length();   i){
                c = expr[i];

                if (!isalnum(c))
                    break;
                
                token  = c;
            }
            std::cout << "Verificare: " << token << 'n';
            
            --i;

            if (CheckOperator(token))
                operators.push(token);
            else
                Infix.push_back(token);
        }
        else if((prioritate = CheckOperator(token))){
            bool numar = false;
            for (  i; i < expr.length();   i){
                c = expr[i];
                token  = c;
#if defined(__SUPPORT_DOUBLE__)
                if (!CheckOperator(token) amp;amp; !isdigit(c) amp;amp; c != '.'){
                    token.erase(token.length() - 1, token.length());
                    break;
                }
#else
                if (!CheckOperator(token) amp;amp; !isdigit(c)){
                    token.erase(token.length() - 1, token.length());
                    break;
                }
#endif
                if (isdigit(c))
                    numar = true;
            }
            --i;
            if (!numar){
                while(!operators.empty() amp;amp; CheckOperator(operators.top()) >= prioritate)
                {
                    Infix.push_back(operators.top());
                    operators.pop();
                }
                operators.push(token);
            }
            else
            {
                Infix.push_back(token);
            }
            
        }
        else if (c == '(')
        {
            operators.push("(");
        }
        else if (c == ')')
        {
            while (!operators.empty())
            {
                if (operators.top() == "("){
                    operators.pop();
                    break;
                }
                Infix.push_back(operators.top());
                operators.pop();
            }
        }
    }
    while (!operators.empty())
    {
        Infix.push_back(operators.top());
        operators.pop();

    }

#if defined(__DEBUG__)
    for (const autoamp; ex : Infix)
        fout << ex << ' ';
    fout << 'n';
#endif

    autoamp; it = Infix.begin();
    for(; it != Infix.end();   it)
    {
        if (CheckOperator(*it))
        {
            if (*it == " ")
            {
                long double b = std::stold(Rezultat.top());
                Rezultat.pop();
                long double a = std::stold(Rezultat.top());
                Rezultat.pop();

                Rezultat.push(std::to_string(a   b));
            }
            else if(*it == "-")
            {
                long double b = std::stold(Rezultat.top());
                Rezultat.pop();
                long double a = std::stold(Rezultat.top());
                Rezultat.pop();

                Rezultat.push(std::to_string(a - b));
            }
            else if(*it == "*")
            {
                long double b = std::stold(Rezultat.top());
                Rezultat.pop();
                long double a = std::stold(Rezultat.top());
                Rezultat.pop();

                Rezultat.push(std::to_string(a * b));
            }
            else if(*it == "/")
            {
                long double b = std::stold(Rezultat.top());
                Rezultat.pop();
                long double a = std::stold(Rezultat.top());
                Rezultat.pop();

                Rezultat.push(std::to_string(a / b));
            }
            else if(*it == "^")
            {
                long double b = std::stold(Rezultat.top());
                Rezultat.pop();
                long double a = std::stold(Rezultat.top());
                Rezultat.pop();

                Rezultat.push(std::to_string(std::powl(a, b)));
            }
            else if(*it == "==")
            {
                long double b = std::stold(Rezultat.top());
                Rezultat.pop();
                long double a = std::stold(Rezultat.top());
                Rezultat.pop();

                Rezultat.push(std::to_string(a == b));
            }
            else if(*it == "pow")
            {
                long double b = std::stold(Rezultat.top());
                Rezultat.pop();
                long double a = std::stold(Rezultat.top());
                Rezultat.pop();

                Rezultat.push(std::to_string(std::powl(a, b)));
            }
        }
        else
        {
            Rezultat.push(*it);
        }
    }
#if defined(__SUPPORT_DOUBLE__)
    fout << Rezultat.top() << 'n';
#else
    fout << std::stol(Rezultat.top()) << 'n';
#endif
    return 0;
}
 

Спасибо!

Редактировать: я опубликовал решение на Github, если оно вам нужно.

Ответ №1:

Не совсем понятно, что вы подразумеваете под «формулами».

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

Присваивание x = y можно рассматривать как просто другой вид выражения. Вы хотите добавить = оператор в свой список поддерживаемых операторов. Просто выберите его приоритет.

Очевидно, что оценщику необходимо отличать переменные от констант и выражений, чтобы он мог сигнализировать об ошибке в каждом из этих случаев:

     x   2 (undefined x)
    2 = 5 (assignment to non-variable)
(1 2) = 3 (same)
 

Обратите внимание, что вы хотите иметь возможность оценивать несколько выражений сейчас, чтобы вы могли оценивать var = 50 , а затем 1 var как два отдельных выражения. Разработайте способ их разделения. ; Символ будет отлично работать для этой цели.

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

Комментарии:

1. Здравствуйте, под формулами я подразумеваю математические формулы (pow, floor и т. Д. (я разместил ссылку)). Кроме того, я уже использую оператор «==» для сравнения, и он работает правильно.

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

3. Спасибо! Мой подход был немного неправильным, поэтому я перекодировал его и сумел заставить его работать так, как предполагалось. Вы можете проверить код здесь , если вам интересно.