Удалите код между #if 0 и #endif при экспорте файла C в новый - PullRequest
0 голосов
/ 09 сентября 2018

Я хочу удалить все комментарии в файле 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 ]

0 голосов
/ 10 сентября 2018

Есть пара программ, 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 с еще большими возможностями.

0 голосов
/ 10 сентября 2018

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

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

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

Подход к обработке текста ограничен, так как он предназначен только для #if 0 ... #endif случая, но это все, что мне нужно на данный момент. Программа на 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;
  }
0 голосов
/ 09 сентября 2018

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

Простой конечный автомат, использующий 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 может достичь.

...