Отметьте несбалансированные круглые скобки

Ниже исходный код — мое решение упражнения 1-24 K&R.

Упражнение 1-24. Напишите программу для проверки программы на языке C на предмет элементарных синтаксических ошибок, таких как несбалансированные круглые скобки, скобки и фигурные скобки. Не забывайте о кавычках, как одинарных, так и двойных, escape-последовательностях и комментариях. (Эта программа сложна, если вы делаете ее в общих чертах.)

В моей программе используются два типа переменных состояния. Скобки(( ), { }, [ ]) и пунктуация (», «», / * * /). Круглые скобки сохраняются в nest[] и знаки препинания сохраняются в state. И условия оператора if в основном используют эти две переменные.

Меня не волновал случай фигурной скобки после открытия скобок и скобок.

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

#include <stdio.h>

/* This program checks if there is unbalanced parentheses, curly braces or brackets.
 * This program doesn't check if there is a newline charcter between a single quote or a double quote.
 * This program doesn't check if there is non-terminated comment, single quote or double quote.
 */

#define NOTHING         0
#define COMMENT         1
#define SINGLE_QUOTE    2
#define DOUBLE_QUOTE    3

#define PARENTHESIS     1
#define CURLY_BRACE     2
#define BRACKET         3

#define MAX_NESTING_LEVEL 100

void check_paren(void);

void main(void)
{
    check_paren();
}

void check_paren(void)
{
    int c;
    int line;
    int state;
    int nest[MAX_NESTING_LEVEL] = {NOTHING};
    int n;

    n = 0;
    line = 1;
    state = NOTHING;
    while ((c = getchar()) != EOF) {
        if ( n > MAX_NESTING_LEVEL -1) {
            printf("error : line %d : exceed MAX_NESTING_LEVELn", line);
            return;
        } else if (c == 'n') {
            ++line;
        } else if (state != COMMENT) {
            if (c == "https://codereview.stackexchange.com/") 
                if ((c = getchar()) == '*')
                    state = COMMENT;
        }
        
        if (state == NOTHING && n == 0) {
            if (c == ''')
                state = SINGLE_QUOTE;
            else if (c == '"')
                state = DOUBLE_QUOTE;
            else if (c == '(')
                nest[n++] = PARENTHESIS;
            else if (c == '{')
                nest[n++] = CURLY_BRACE;
            else if (c == '[')
                nest[n++] = BRACKET;
            else if (c == ')') {
                printf("error : line %d : unmatched )n", line);
                return;
            } else if (c == '}'){
                printf("error : line %d : unmatched }n", line);
                return;
            } else if (c == ']'){
                printf("error : line %d : unmatched ]n", line);
                return;
            }
        } else if (state == NOTHING && nest[n-1] == PARENTHESIS) {
            if (c == ')')
                nest[--n] = NOTHING;
            else if (c == '(')
                nest[n++] = PARENTHESIS;
            else if (c == '[')
                nest[n++] = BRACKET;
            else if (c == ''')
                state = SINGLE_QUOTE;
            else if (c == '"')
                state = DOUBLE_QUOTE;
            else if (c == '}') {
                printf("error : line %d : ( + }n", line);
                return;
            }
            else if (c == ']') {
                printf("error : line %d : ( + ]n", line);
                return;
            }
        } else if (state == NOTHING && nest[n-1] == CURLY_BRACE) {
            if (c == '}')
                nest[--n] = NOTHING;
            else if (c == '(')
                nest[n++] = PARENTHESIS;
            else if (c == '{')
                nest[n++] = CURLY_BRACE;
            else if (c == '[')
                nest[n++] = BRACKET;
            else if (c == ''')
                state = SINGLE_QUOTE;
            else if (c == '"')
                state = DOUBLE_QUOTE;
            else if (c == ')') {
                printf("error : line %d : { + )n", line);
                return;
            }
            else if (c == ']') {
                printf("error : line %d : { + ]n", line);
                return;
            }
        } else if (state == NOTHING && nest[n-1] == BRACKET) {
            if (c == ']')
                nest[--n] = NOTHING;
            else if (c == '(')
                nest[n++] = PARENTHESIS;
            else if (c == ''')
                state = SINGLE_QUOTE;
            else if (c == ')') {
                printf("error : line %d : [ + )n", line);
                return;
            }
            else if (c == '}') {
                printf("error : line %d : [ + }n", line);
                return;
            }
        } else {
            if (state == COMMENT && c == '*') {
                if ((c = getchar()) == "https://codereview.stackexchange.com/") 
                    state = NOTHING;
            } else if (c == '\') 
                getchar();
            else if (state == SINGLE_QUOTE && c == ''') 
                state = NOTHING;
            else if (state == DOUBLE_QUOTE && c == '"') 
                state = NOTHING;
        }
    }
}

1 ответ
1

Вы можете присвоить номер state вместо того, чтобы просто держать его в char. Вы все еще можете использовать значение символа EOF / ноль как «магию». Это значительно упростило бы отладку, и вы можете просто назначить символ чтения для nest напрямую. Это удалило бы много кода.

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

char и int также может использоваться в switch заявления вместо if заявления. Когда вы думаете о «машине состояний», то, вероятно, сначала на ум приходит цикл с переключателем (в любом случае, когда не выполняется функциональное программирование).

Например

switch(c):
case '(':
case '[':
...
    nest[n++] = c;
    break;
...

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

  • Вы имеете в виду переменную c бесполезно, а затем while ((c = getchar()) != EOF) может быть переписан while ((state = getchar()) != EOF)?

    — на ол

  • Тот факт, что у вас могут быть escape-последовательности и два разных двухсимвольных комментария, может потребовать некоторых обходных решений. Но это случай с твоим текущим int как я полагаю.

    — Маартен Бодевес


  • Нет, поцарапайте это, такие строки, как else if (state == SINGLE_QUOTE && c == ''') не будет работать; в конце концов, состояние зависит от прошлого. Но во многих случаи ты мог бы просто выполнить state = c

    — Маартен Бодевес


  • Не знаю, я на 100% понимаю ваш комментарий. Я думаю ты говоришь else if (c == '"') state = DOUBLE_QUOTE; возможно else if (c == '"') state = c и else if (c == '(') nest[n++] = PARENTHESIS; возможно else if (c == '(') nest[n++] = c; Если моя мысль верна. Фактически вы имеете в виду, что мое определение макроса можно заменить символьной переменной (c). Это будет вопрос стиля. Длина кода не изменится.

    — на ол


  • 1

    Добавлен пример … меньше конверсии всегда означает меньше кода. Во-первых, вы можете избавиться от большинства #define заявления.

    — Маартен Бодевес


Добавить комментарий

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