Избавляемся от всех комментариев в Си - PullRequest
0 голосов
/ 03 марта 2019

Сейчас этот код не удаляет встроенные комментарии, как я могу изменить его, чтобы он также удалял встроенные комментарии?

FILE *output;
output = fopen("preprocess_output.c", "w");

while (fgets(line, LINE_LENGTH, file) != NULL)
{
    for (int i = 0; i < strlen(line); i++)
    {
        if (line[i]  ==  '/' && line[i + 1]  ==  '/')
        {
            comment_lines++;
        }
        else
        {
            fprintf(output, line);
        }
        if (line[i] != '\n' && line[i] != '\t')
        {
            non_blank++;
            break;
        }   
    }
}

Ответы [ 3 ]

0 голосов
/ 03 марта 2019

Вам нужно будет отсканировать файл на наличие "\\" или "\*" в любом месте кода, который указывает комментарий ( Следовательно, как вы обнаружите комментарийв вашем коде ), игнорируйте их, а затем проверьте, где они заканчиваются '\n' и "*/" соответственно и продолжайте писать оттуда ...

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

int main(void) {
    FILE * file;
    FILE * output;
    if (fopen_s(&file, "some_src.c", "r") != 0) {
        fprintf(stderr, "File reading failure!");
        return 1;
    }
    if (fopen_s(&output, "preprocess_output.c", "w") != 0) {
        fprintf(stderr, "File writing failure!");
        return 1;
    }
    int comment = 0;
    char prev_ch, ch;
    for (prev_ch = fgetc(file), ch = fgetc(file); ch != EOF; prev_ch = ch, ch = fgetc(file)) {
        if (comment == 0 && prev_ch == '/')
        {
            if (ch == '/')
                comment = 1;
            else if (ch == '*')
                comment = 2;
        }
        if (comment == 0)
            fprintf(output, "%c", prev_ch);
        if (comment == 1 && prev_ch != '\\' && ch == '\n')
            comment = 0;
        if (comment == 2 && prev_ch == '*' && ch == '/')
        {
            ch = fgetc(file);
            comment = 0;
        }
    }
    if (comment == 0)
        fprintf(output, "%c", prev_ch);
    fclose(file);
    fclose(output);
    return 0;
}

Примечание: Поскольку многие отмечали, почему я использовал \ косые черты в коде вместо /, попробуйте это Демо , чтобы выяснить, почему?

0 голосов
/ 05 марта 2019

Вот небольшая программа, которая отбирает комментарии на Си почти во всех случаях.

/* strip C comments by chqrlie */

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

/* read the next byte from the C source file, handing escaped newlines */
int getcpp(FILE *fp, int *lineno_p) {
    int ch;
    while ((ch = getc(fp)) == '\\') {
        if ((ch = getc(fp)) != '\n') {
            ungetc(ch, fp);
            return '\\';
        }
        *lineno_p += 1;
    }
    if (ch == '\n')
        *lineno_p += 1;
    return ch;
}

int main(int argc, char *argv[]) {
    FILE *fp = stdin, *ft = stdout;
    const char *filename = "<stdin>";
    int ch, lineno;

    if (argc > 1) {
        if ((fp = fopen(filename = argv[1], "r")) == NULL) {
            fprintf(stderr, "Cannot open input file %s: %s\n",
                    filename, strerror(errno));
            return 1;
        }
    }
    if (argc > 2) {
        if ((ft = fopen(argv[2], "w")) == NULL) {
            fprintf(stderr, "Cannot open output file %s: %s\n",
                    argv[2], strerror(errno));
            return 1;
        }
    }
    lineno = 1;
    while ((ch = getcpp(fp, &lineno)) != EOF) {
        int startline = lineno;
        if (ch == '/') {
            if ((ch = getcpp(fp, &lineno)) == '/') {
                /* single-line comment */
                while ((ch = getcpp(fp, &lineno)) != EOF && ch != '\n')
                    continue;
                if (ch == EOF) {
                    fprintf(stderr, "%s:%d: unterminated single line comment\n",
                            filename, startline);
                    break;
                }
                putc('\n', ft);  /* replace comment with newline */
                continue;
            }
            if (ch == '*') {
                /* multi-line comment */
                int lastc = 0;
                while ((ch = getcpp(fp, &lineno)) != EOF) {
                    if (ch == '/' && lastc == '*') {
                        break;
                    }
                    lastc = ch;
                }
                if (ch == EOF) {
                    fprintf(stderr, "%s:%d: unterminated comment\n",
                            filename, startline);
                    break;
                }
                putc(' ', ft);  /* replace comment with single space */
                continue;
            }
            putc('/', ft);
            /* keep parsing to handle n/"a//"[i] */
        }
        if (ch == '\'' || ch == '"') {
            int sep = ch;
            const char *const_type = (ch == '"') ? "string" : "character";

            putc(sep, ft);
            while ((ch = getcpp(fp, &lineno)) != EOF) {
                putc(ch, ft);
                if (ch == sep)
                    break;;
                if (ch == '\\') {
                    if ((ch = getcpp(fp, &lineno)) == EOF)
                        break;
                    putc(ch, ft);
                }
                if (ch == '\n') {
                    fprintf(stderr, "%s:%d: unescaped newline in %s constant\n",
                            filename, lineno - 1, const_type);
                    /* This is a syntax error but keep going as if constant was terminated */
                    break;
                }
            }
            if (ch == EOF) {
                fprintf(stderr, "%s:%d: unterminated %s constant\n",
                        filename, startline, const_type);
                break;
            }
            continue;
        }
        putc(ch, ft);
    }
    if (fp != stdin)
        fclose(fp);
    if (ft != stdout)
        fclose(ft);
    return 0;
}

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

  • одним из таких угловых случаев является то, что код не анализирует триграфы, устаревшая функция, которая может использоваться для сокрытия \ символов.
0 голосов
/ 03 марта 2019

в следующем решении есть один проход по линии.Если комментарий был найден (//), мы прекращаем работу и печатаем его.поддержка (/* */) требует больше работы.

while (fgets(line, LINE_LENGTH, file) != NULL)
{
    size_t len = strlen(line);
    size_t i;

    for (i=0; i<len; i++)
    {
        if (line[i]=='/' && line[i + 1]=='/')
        {
            line[i] = '\0';
            break;
        }
    }
    fprintf(output, "%s", line);
}

обратите внимание на две точки в дополнение к логике:

  • при печати с использованием printf, всегда используйтестрока формата.Если строка содержит%, это может привести к непредвиденным последствиям.

  • не помещайте strlen в состояние цикла.Он генерирует множество ненужных циклов для вычисления длины.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...