ошибка синтаксического анализа при отладке шины

Это мой первый раз, когда я использую шину (из репозиториев Ubuntu), и я сразу же попал в WTF. Сообщение об ошибке:

nightcracker@nightcracker-pc:~/c/brainfuck$ splint brainfuck.c
Splint 3.1.2 --- 03 May 2009

brainfuck.c:17:6: Parse Error. (For help on parse errors, see splint -help
               parseerrors.)
*** Cannot continue.

Теперь, по-видимому, он видит что-то неправильное в строке 16, столбце 6. Давайте проверим это (выкладывая полный код):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum {
    CELL_CHUNK_SIZE = 1024,
};

typedef unsigned char cell;

int main(int argc, char *argv[]) {
    if (argc < 1) {
        fprintf(stderr, "ERROR: Not enough arguments\n");
        return 1;
    }

    FILE  *srcfile; // source file << THIS LINE APPARENTLY IS WRONG
    long srclen; // source file size
    char *bf; // brainfuck code file in memory

    char *ip; // instruction pointer
    cell *cells; // brainfuck cells
    cell *newcells; // used for creating a new chunk of cells
    cell *cp; // cell pointer
    unsigned long numcells = CELL_CHUNK_SIZE; // amount of current cells
    unsigned nest; // current nesting
    int buf; // i/o buffer

    srcfile = fopen(argv[1], "rb");
    if (srcfile == NULL) {
        fprintf(stderr, "ERROR: Couldn't open source file\n");
        return 2;
    }

    // get source file length
    fseek(srcfile, 0, SEEK_END);
    srclen = ftell(srcfile);
    fseek(srcfile, 0, SEEK_SET);

    // allocate memory for source file
    bf = malloc(srclen);
    if (bf == NULL) {
        fprintf(stderr, "ERROR: Couldn't allocate memory for source file\n");
        return 3;
    }

    // read source file in memory
    if (srclen != fread(bf, sizeof(char), srclen, srcfile)) {
        fprintf(stderr, "ERROR: Error while reading source file\n");
        free(bf);
        return 4;
    }

    fclose(srcfile);

    cells = malloc(CELL_CHUNK_SIZE * sizeof(cell));
    memset(cells, 0, CELL_CHUNK_SIZE);

    if (cells == NULL) {
        fprintf(stderr, "ERROR: Memory allocation failed\n");
        free(bf);
        free(cells);
        return 5;
    }

    cp = cells; // cell pointer initialized to most-left cell
    ip = bf; // instruction pointer initialized to first character
    nest = 0;

    while (ip >= bf && ip <= (bf + srclen)) {
        switch (*ip) {
            case '+':
                (*cp)++;
                break;
            case '-':
                (*cp)--;
                break;
            case '>':
                cp++;
                if ((cp - cells) == numcells) {
                    newcells = realloc(cells, (numcells + CELL_CHUNK_SIZE) * sizeof(cell)); // allocate memory for new chunk

                    if (newcells == NULL) {
                        fprintf(stderr, "ERROR: Memory allocation failed\n");
                        free(bf);
                        free(cells);
                        return 5;
                    }

                    cp = newcells + (cp - cells); // point cell pointer to cell in new chunk
                    cells = newcells; // point cells to new memory location (if altered)
                    memset(cp, 0, CELL_CHUNK_SIZE); // initialize new chunk
                    numcells += CELL_CHUNK_SIZE;
                }
                break;
            case '<':
                cp--;
                break;
            case '.':
                putchar(*cp);
                break;
            case ',':
                if ((buf = getchar()) != EOF) {
                    *cp = (unsigned char) buf;
                } else *cp = 0;
                break;
            case '[':
                if (!(*cp)) {
                    ip++; // move past the opening bracket
                    while (nest > 0 || *ip != ']') { // skip to matching ]
                        if (*ip == '[') nest++; // enter nest
                        if (*ip == ']') nest--; // leave nest (or main loop, in which nesting > 0 fails)

                        ip++; // move right
                    }

                }
                break;
            case ']':
                if (*cp) {
                    ip--; // move before the closing bracket
                    while (nest > 0 || *ip != '[') { // rewind to matching [
                        if (*ip == '[') nest--; // leave nest (or main loop, in which nesting > 0 fails)
                        if (*ip == ']') nest++; // enter nest

                        ip--; // move left
                    }
                    ip--; // move before the opening bracket
                }
                break;
        }

        ip++; // move to next instruction
    }


    free(cells);
    free(bf);
    return 0;
}

Обратите внимание, что эта программа компилируется без ошибок (gcc -Wall -std=c99 brainfuck.c) и работает нормально.

Примечание: если вас оскорбляет название brainfuck, смиритесь с этим. Это язык программирования, названный так автором, и я уважаю и использую это имя.


person orlp    schedule 27.03.2011    source источник


Ответы (2)


Знает ли шина C99?

Попробуйте /* ... */ вместо // ... и переместите объявления перед любым кодом

person pmg    schedule 27.03.2011
comment
OMG Я никогда не знал, что однострочные комментарии были введены в c99. Мой компилятор никогда не жаловался, даже без -std=c99. Хотя, к сожалению, это не решает мою проблему. - person orlp; 27.03.2011
comment
Я добавил в свой пост еще одну вещь C99 (объявления, смешанные с кодом, тоже новые) - person pmg; 27.03.2011
comment
@nightcracker: довольно много компиляторов приняли // как расширение, но официально оно не было частью языка до C99. - person Jerry Coffin; 27.03.2011
comment
Тогда считается ли это плохой практикой? Я считаю, что это намного проще и лучше, поскольку не блокирует комментирование блоков кода. - person orlp; 27.03.2011
comment
Принятый. Перемещение объявлений сделало свое дело. Тоже никогда этого не знал ›.‹ Погуглив, я нашел это: bugs.debian .org/cgi-bin/bugreport.cgi?bug=369264 - person orlp; 27.03.2011
comment
Я думаю, что это нормально (неплохая практика) использовать // ... комментарии и объявления, смешанные с кодом. Если ваш источник никогда не увидит компилятор C89 (без дополнений) или какой-либо старомодный инструмент (например, splint), вы не столкнетесь с какими-либо проблемами. - person pmg; 27.03.2011
comment
Что бы вы порекомендовали для фильтрации распространенных ошибок вместо шины? - person orlp; 27.03.2011
comment
@nightcracker: я обычно пишу C89, поэтому мне подходит шина ... но в наши дни компиляторы довольно хорошо ловят распространенные ошибки и глупые ошибки. Запустите диагностику вашего компилятора. - person pmg; 27.03.2011
comment
Моя диагностика компилятора в порядке (-Wall). Я подумал, что, может быть, он не все понял, но они действительно очень хороши в наши дни. Хм, может быть, мне не стоило читать K&R версии 1 как мою первую (и только ATM) книгу на C. - person orlp; 27.03.2011
comment
Мой вызов gcc по умолчанию для C99 улавливает 2 сравнения между подписанным и неподписанным (строки 48 и 80) и 1 переключатель без регистра по умолчанию (строка 71) при компиляции вашего кода. - person pmg; 27.03.2011

Вы также можете использовать +slashslashcomment при вызове splint. В таком случае:

splint +slashslashcomment brainfuck.c


Приложение B к Руководству по использованию шин.

P:- косая черта косая чертакомментарий

// используется комментарий. ISO C99 допускает // комментарии, а более ранние стандарты — нет.

(поместил бы это в комментарий, но не имеет необходимой репутации)

person EchoLynx    schedule 19.10.2016