Как из строки построить дерево операций?

327
16 ноября 2017, 04:45

Есть на входе строка, допустим известное char expr="2+2*2" которое должно дать 6.

Допустим определены операции enum operations { opadd = 1 , opmul = 2 , opconst = 3 };

Тогда можно определить дерево struct optree { operations op, int arg1, int arg2}; такой структурой (или другой).

Для 2+2*2 получится такой массив:

{/*0*/opadd,1,2},{/*1*/opconst,2,0},{/*2*/opmull,3,4},{/*3*/opconst,2,0 },{/*4*/opconst,2,0}

Обработать массив не получится сразу, его нужно как-то отсортировать что б приоритет умножения стал выше, т.е. массив станет таким (теоретически)

{/*0*/opconst,2,0},{/*1*/opconst,2,0},{/*2*/opconst,2,0},{/*3*/opmul,1,2},{/*4*/opadd,0,1}
Т.е. получили фактически байт-код, выполняя который последовательно можно получить 6.

Где об этом можно почитать, как эту задачу можно решить?

Answer 1

Данное преобразование называется Обра́тная по́льская нота́ция (или обратная польская запись) — форма записи математических и логических выражений, в которой операнды расположены перед знаками операций.

Сегодня похожая форма используется в Java-байткоде, CLR(c#) байткоде и AS3 (adobe flash) байткоде .

Ссылки Обратная польская запись и её реализация

Пример из википедии

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#define STKDPTH 32 /* Глубина стека */
/* Значения, возвращаемые функцией parse */
#define VAL  0  /* В стек занесено новое значение */
#define ADD  1  /* Сложение */
#define SUB  2  /* Вычитание */
#define MUL  3  /* Умножение */
#define DIV  4  /* Деление */
#define SOF -1  /* Переполнение стека */
#define SUF -2  /* В стеке недостаточно операндов */
#define UNK -3  /* Неопознанное значение */
/* Глобальные переменные */
int scount;
double stack[STKDPTH];
/* Функция распознавания аргументов */
int parse(char *);
/* Точка входа */
int main(int argc, char **argv)
{
    /* Организуем цикл для перебора аргументов командной строки */
    while (*++argv) {
        /* Пытаемся распознать текущий аргумент как число или
         * символ арифметической операции */
        switch (parse(*argv)) {
            case VAL: continue;
            /* Вычисляем */
            case ADD:
                stack[scount - 1] += stack[scount];
                break;
            case SUB:
                stack[scount - 1] -= stack[scount];
                break;
            case MUL:
                stack[scount - 1] *= stack[scount];
                break;
            case DIV:
                if (stack[scount] != 0) {
                    stack[scount - 1] /= stack[scount];
                    break;
                } else {
                    fprintf(stderr, "Деление на ноль!\n");
                    return(1);
                }
            /* Обработка ошибок */
            case SUF:
                fprintf(stderr, "Недостаточно операндов!\n");
                return(1);
            case SOF:
                fprintf(stderr, "Переполнение стека!\n");
                return(1);
            case UNK:
                fprintf(stderr, "Неопознанный аргумент!\n");
                return(1);
        }
    }
    /* Вывести результат */
    auto int i;
    for (i = 0; i < scount; i++) printf("%0.3f\n", stack[i]);
    return(0);
}
int parse(char *s)
{
    double tval = 0;
    char * endptr;
    /* Распознаем знаки арифметических операций */
    switch (*s) {
        case '-':
            /* Если минус является первым и не последним символом аргумента,
             * значит пользователь ввел отрицательное число и опознавать его
             * как операцию вычитания не нужно */
            if (*(s+1) != '\0') break;
            if (scount >= 2) {
                scount -= 1;
                return(SUB);
            }
            else return(SUF);
        case '+':
            if (scount >= 2) {
                scount -= 1;
                return(ADD);
            }
            else return(SUF);
        case 'x':
            if (scount >= 2) {
                scount -= 1;
                return(MUL);
            }
            else return(SUF);
        case '/':
            if (scount >= 2) {
                scount -= 1;
                return(DIV);
            }
            else return(SUF);
    }
    errno = 0;
    /* Пытаемся сконвертировать строковый аргумент в число */
    tval = strtod(s, &endptr);
    /* Вернуть ошибку `неопознанный аргумент' в случае неудачи */
    if (errno != 0 || *endptr != '\0') return(UNK);
    /* Проверяем, есть ли свободное место в стеке
     * и сохраняем в нем операнд, иначе возвращаем ошибку переполнения */
    if (scount < STKDPTH) stack[scount++] = tval;
    else return(SOF);
    return(VAL);
}
READ ALSO
Больше случайности в C++ [дубликат]

Больше случайности в C++ [дубликат]

На данный вопрос уже ответили:

481
Наложение Images в PictureBox

Наложение Images в PictureBox

Нужно в PictureBox наложить картинки одну на другую фон у них прозрачный по этому не должны перекрывать друг друга

383
Вывод из функции в c++

Вывод из функции в c++

Всем здравствуйте, следующая проблема: У меня есть функция "showArray" она выводит случайные числа, я в "main" приписываю её, а как мне теперь увидеть...

328
Из статического массива в массив с использованием указателей (C++)

Из статического массива в массив с использованием указателей (C++)

Доброго времени сутокЕсть код ниже, который нужно переделать с использованием указателей

277