Удалить код между #if 0 и #endif при экспорте файла C в новый

Я хочу удалить все комментарии в toy.c файл. Из Удалить комментарии из кода C/C++ я вижу, что я мог бы использовать

gcc -E -fpreprocessed -P -dD toy.c

Но некоторые из моего кода (скажем, устаревшие функции, которые я не хочу компилировать) заключены между #if 0 а также endif как будто они были закомментированы.

  • С одной стороны, приведенная выше команда не удаляет этот тип "комментария", потому что его удаление возможно только во время расширения макроса, которое -fpreprocessed предотвращает;
  • С другой стороны, у меня есть другие макросы, которые я не хочу расширять, поэтому удаление -fpreprocessed плохая идея

Я вижу здесь дилемму. Есть ли выход из этой ситуации? Благодарю.


Следующий пример игрушки "toy.c" достаточен для иллюстрации проблемы.

#define foo 3  /* this is a macro */

// a toy function
int main (void) {
  return foo;
  }

// this is deprecated
#if 0
int main (void) {
  printf("%d\n", foo);
  return 0;
  }
#endif

gcc -E -fpreprocessed -P -dD toy.c дает

#define foo 3
int main (void) {
  return foo;
  }
#if 0
int main (void) {
  printf("%d\n", foo);
  return 0;
  }
#endif

в то время как gcc -E -P toy.c дает

int main (void) {
  return 3;
  }

3 ответа

Решение

Спасибо за два других ответа.

Теперь я знаю о unifdef и sunifdef. Я счастлив узнать о существовании этих инструментов и о том, что я не единственный, кто хочет проводить такую ​​очистку кода.

Я также написал "rm_if0_endif.c" (прилагается ниже) для удаления #if 0 ... #endif блок, которого мне достаточно. Его философия основана на обработке текста. Сканирует входной скрипт C, находя #if 0 и правильное вложение endif, так что этот блок может быть опущен при копировании с символа на символ.

Подход к обработке текста ограничен, так как он предназначен для #if 0 ... #endif только случай, но это все, что мне нужно на данный момент. Программа A C - не единственный способ обработки текста такого рода. Ответ Жан-Франсуа Фабра демонстрирует, как это сделать на Python. Я также могу сделать что-то подобное в R, используя readLines, startsWith а также writeLines, Я решил сделать это на C, поскольку я еще не эксперт в C, поэтому эта задача заставляет меня учиться. Вот демонстрация моего "rm_if0_endif.c". Обратите внимание, что программа может объединить несколько файлов C и добавить заголовок для каждого файла.

исходный входной файл "input.c"

#define foo 3  /* this is a macro */

// a toy function
int test1 (void) {
  return foo;
  }

#if 0

#undef foo
#define foo 4

#ifdef bar
  #warning "??"
#endif

// this is deprecated
int main (void) {
  printf("%d\n", foo);
  return 0;
  }

#endif

// another toy
int test2 (void) {
  return foo;
  }

Предварительная обработка gcc "gcc_output.c" (взята в качестве входных данных для моей программы)

gcc -E -fpreprocessed -P -dD input.c > gcc_output.c

#define foo 3
int test1 (void) {
  return foo;
  }
#if 0
#undef foo
#define foo 4
#ifdef bar
  #warning "??"
#endif
int main (void) {
  printf("%d\n", foo);
  return 0;
  }
#endif
int test2 (void) {
  return foo;
  }

окончательный вывод "final_output.c" из моей программы

"rm_if0_endif.c" имеет функцию полезности pattern_matching и рабочая лошадка rm_if0_endif:

void rm_if0_endif (char *InputFile,
                   char *OutputFile, char *WriteMode, char *OutputHeader);

Прикрепленный файл ниже имеет main функция, делающая

rm_if0_endif("gcc_output.c",
             "final_output.c", "w", "// this is a demo of 'rm_if0_endif.c'\n");

Это производит:

// this is a demo of 'rm_if0_endif.c'
#define foo 3
int test1 (void) {
  return foo;
  }

int test2 (void) {
  return foo;
  }

Приложение: "rm_if0_endif.c"

#include <stdio.h>
int pattern_matching (FILE *fp, const char *pattern, int length_pattern) {
  int flag = 1;
  int i, c;
  for (i = 0; i < length_pattern; i++) {
    c = fgetc(fp);
    if (c != pattern[i]) {
      flag = 0; break;
      }
    }
  return flag;
  }
void rm_if0_endif (char *InputFile,
                   char *OutputFile, char *WriteMode, char *OutputHeader) {
  FILE *fp_r = fopen(InputFile, "r");
  FILE *fp_w = fopen(OutputFile, WriteMode);
  fpos_t pos;
  if (fp_r == NULL) perror("error when opening input file!");
  fputs(OutputHeader, fp_w);
  int c, i, a1, a2;
  int if_0_flag, if_flag, endif_flag, EOF_flag;
  const char *if_0 = "if 0";
  const char *endif = "endif";
  EOF_flag = 0;
  while (EOF_flag == 0) {
    do {
      c = fgetc(fp_r);
      while ((c != '#') && (c != EOF)) {
        fputc(c, fp_w);
        c = fgetc(fp_r);
        }
      if (c == EOF) {
        EOF_flag = 1; break;
        }
      fgetpos(fp_r, &pos);
      if_0_flag = pattern_matching(fp_r, if_0, 4);
      fsetpos(fp_r, &pos);
      if (if_0_flag == 0) fputc('#', fp_w);
      } while (if_0_flag == 0);
    if (EOF_flag == 1) break;
    a1 = 1; a2 = 0;
    do {
      c = fgetc(fp_r);
      while (c != '#') c = fgetc(fp_r);
      fgetpos(fp_r, &pos);
      if_flag = pattern_matching(fp_r, if_0, 2);
      fsetpos(fp_r, &pos);
      if (if_flag == 1) a1++;
      fgetpos(fp_r, &pos);
      endif_flag = pattern_matching(fp_r, endif, 5);
      fsetpos(fp_r, &pos);
      if (endif_flag == 1) a2++;
      } while (a1 != a2);
    for (i = 0; i < 5; i++) c = fgetc(fp_r);
    if (c == EOF) {
      EOF_flag == 1;
      }
    }
  fclose(fp_r);
  fclose(fp_w);
  }
int main (void) {
  rm_if0_endif("gcc_output.c",
               "final_output.c", "w", "// this is a demo of 'rm_if0_endif.c'\n");
  return 0;
  }

Там есть пара программ, sunifdef ("Сын unifdef ", которая доступна от unifdef) и coan, который может быть использован, чтобы делать то, что вы хотите. Вопрос Есть ли препроцессор C, который устраняет блоки #ifdef на основе значений, определенных / неопределенных? есть ответы, которые обсуждают эти программы.

Например, учитывая "xyz37.c":

#define foo 3  /* this is a macro */

// a toy function
int main (void) {
  return foo;
  }

// this is deprecated
#if 0
int main (void) {
  printf("%d\n", foo);
  }
#endif

С помощью sunifdef

sunifdef -DDEFINED -ned < xyz37.c

дает

#define foo 3  /* this is a macro */

// a toy function
int main (void) {
  return foo;
  }

// this is deprecated

и с учетом этого файла "xyz23.c":

#if 0
This is deleted
#else
This is not deleted
#endif

#if 0
Deleted
#endif

#if defined(XYZ)
XYZ is defined
#else
XYZ is not defined
#endif

#if 1
This is persistent
#else
This is inconsistent
#endif

Программа

sunifdef -DDEFINE -ned < xyz23.c

дает

This is not deleted

#if defined(XYZ)
XYZ is defined
#else
XYZ is not defined
#endif

This is persistent

Это, я думаю, то, что вы после. -DDEFINED варианты кажутся необходимыми; выберите любое имя, которое вы не используете в своем коде. Вы могли бы использовать -UNEVER_DEFINE_THIS вместо этого, если вы предпочитаете. -ned Опция оценивает постоянные условия и исключает соответствующий код. Без этого постоянные условия, такие как 0 а также 1 не устранены.

Я использовал sunifdef счастливо в течение ряда лет (посягая на десятилетие). Я еще не нашел, что это сделало ошибку, и я использовал это, чтобы убрать некоторые отвратительно заумные наборы 'ifdeffery'. Программа coan это развитие sunifdef с еще большими возможностями.

Препроцессор не делает исключений. Вы не можете использовать это здесь, чтобы сделать это.

Простой конечный автомат, использующий python, может работать. Это даже обрабатывает вложенность (ну, может быть, не все случаи покрыты как вложенные #if 0 но вы можете сравнить источник до и после и вручную проверить). Также закомментированный код не поддерживается (но кажется, что он у вас есть)

вход (немного более сложный, чем ваш для демонстрации):

#define foo 3
int main (void) {
  return foo;
  }
#if 0
int main (void) {
  #ifdef DDD
  printf("%d\n", foo);
  #endif
  }
#endif

void other_function()
{}

Теперь код, используя регулярные выражения для обнаружения #if & #endif,

import re
rif0 = re.compile("\s*#if\s+0")
rif = re.compile("\s*#(if|ifn?def)")
endif = re.compile("\s*#endif")

if_nesting = 0
if0_nesting = 0
suppress = False

with open("input.c") as fin, open("output.c","w") as fout:
    for l in fin:
        if rif.match(l):
            if_nesting += 1
            if rif0.match(l):
                suppress = True
                if0_nesting = if_nesting
        elif endif.match(l):
            if if0_nesting == if_nesting:
                suppress = False
            if_nesting -= 1
            continue  # don't write the #endif

        if not suppress:
            fout.write(l))

выходной файл содержит:

#define foo 3
int main (void) {
  return foo;
  }

void other_function()
{}

так что вложение работало и #if 0 часть была успешно удалена. Не то, что sed "/#if 0/,/#endif/d можно достичь.

Другие вопросы по тегам