Разбор строк уравнений в c с использованием scanf - PullRequest
0 голосов
/ 13 сентября 2011

Мне нужно проанализировать ввод от пользователя, который может иметь любое количество вариантов: 1 + 1 4 (3-0) = x 1 * (3) -8

Как мне сделать это, используя scanf, чтобы получить raw_input, затем разделить все различные значения и сказать, является ли это строкой, т.е.

Это то, о чем я думал

    char * raw_input;
    scanf("%s",raw_input);

Требуется массив символов, а затем мне просто нужно разделить и преобразовать в один элемент. Каков наилучший способ ввода и (разбиение и преобразование)

Спасибо

Ответы [ 7 ]

4 голосов
/ 13 сентября 2011

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

Например, чтобы разобрать выражения в такой форме (1+ (3 * 4 + x) * y) +1, вы можете написать такую ​​грамматику:

Expression -> Addition | null
Addition -> Multiplication RestOfAddition
RestOfAddition -> null | + Addition
Multiplication -> Element RestOfMultiplication
RestOfMultiplication -> null | * Element
Element -> number | variable | ( Expression )

Затем в вашей программе для каждого нетерминала в этой грамматике (те, что слева от ->) вы пишете одну функцию, например:

ExpTree *Expression(char *exp, int *position)
{
    if (exp[*position])
    {
        ExpTree *node = malloc(sizeof(*node));
        node->type = LAMBDA;
        node->value = 0;
        return node;
    }
    else
        return Addition(exp, position);
}

ExpTree *Addition(char *exp, int *position)
{
    ExpTree *node = malloc(sizeof(*node));
    node->type = ADDITION;
    node->left = Multiplication(exp, position);
    node->right = RestOfAddition(exp, position);
    return node;
}

ExpTree *RestOfAddition(char *exp, int *position)
{
    ExpTree *node;
    if (exp[*position] == '+')
    {
        ++*position;
        return Addition(exp, position);
    }
    else
    {
        ExpTree *node = malloc(sizeof(*node));
        node->type = LAMBDA;
        node->value = 0;
        return node;
    }
}

Аналогично, Multiplication и RestOfMultiplication будут записаны как функции.

ExpTree *Element(char *exp, int *position)
{
    if (exp[*position] == '(')
    {
        ExpTree *node;
        ++*position;
        node = Expression(exp, position);
        if (!exp[*position] != ')')
             printf("Expected ) at position %d\n", *position);
        else
             ++*position;
        return node;
    }
    else if (exp[*position] == ')')
    {
        printf("Unexpected ) at position %d\n", *position);
        return NULL;
    }
    else if (exp[*position] >= '0' && exp[*position] <= '9')
    {
        ExpTree *node = malloc(sizeof(*node));
        node->type = INTEGER;
        node->value = extract_int(exp, position);
        return node;
    }
    else if ((exp[*position] >= 'a' && exp[*position] <= 'z') ||
             (exp[*position] >= 'A' && exp[*position] <= 'Z') ||
             exp[*position] == '_')
    {
        ExpTree *node = malloc(sizeof(*node));
        node->type = VARIABLE;
        node->value = extract_variable(exp, position);
        return node;
    }
    else
    {
        printf("Warning: unexpected character %c in location %d\n", exp[*position], *position);
        return NULL;
    }
}

Где extract_int и extract_variable - это две функции, которые принимают выражение и позицию в нем, продолжая, пока они видят число (или букву в функции extract_variable), они строят число (переменную) из строки выражения и вернуть его, установив позицию после того, где они закончили.

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

0 голосов
/ 13 сентября 2011

Не используйте scanf. Используйте getchar и применяйте алгоритм Shunting Yard .

0 голосов
/ 13 сентября 2011

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

Но в вашем случае это будет слишком долго

0 голосов
/ 13 сентября 2011

Вы можете использовать:

  • flex, бесплатный генератор лексеров.
  • Итератор для каждой строки.Просто пройдите всю строку и выберите все предметы, которые хотите.strtok () может быть полезен здесь.Или сделайте большой цикл и просто читайте вещи за символ, пока не получите весь токен.
  • Регулярно через re2c (это то, что используется в PHP)

После разделения строки на токеныВам нужно будет разобрать его.Вам понадобится yacc или парсер ручной работы (обычно это рекурсивный спуск ).

0 голосов
/ 13 сентября 2011

Вам нужен лексический анализатор и парсер.Вы можете попробовать lex и yacc, или их более новые аналоги flex и bison.

0 голосов
/ 13 сентября 2011
char * raw_input;
scanf("%s",raw_input);

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

Вам необходимо malloc требуемых байтов и указать raw_input.Затем выполните операции с этими ячейками памяти.

0 голосов
/ 13 сентября 2011

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

...