Как показать «предварительно обработанный» код игнорирования включает в себя с GCC - PullRequest
0 голосов
/ 26 февраля 2019

Я хотел бы знать, возможно ли вывести «предварительно обработанный» код с помощью gcc, но «игнорирование» (без расширения) включает в себя:

ES Я получил это основное:

#include <stdio.h>
#define prn(s) printf("this is a macro for printing a string: %s\n", s);

int int(){
char str[5] = "test"; 
prn(str);
return 0;
}

Я запускаю gcc -E main -o out.c

Я получил:

/*
all stdio stuff
*/

int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);
return 0;
}

Я хотел бы вывести только:

#include <stdio.h>
int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);
return 0;
}

или, по крайней мере, просто

int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);
return 0;
}

PS: было бы здорово, если бы было возможно расширить "локальные" "" включает и не расширять "глобальные" <> включает

Ответы [ 5 ]

0 голосов
/ 26 февраля 2019

Вы можете использовать -dI для отображения директив #include и последующей обработки выходных данных препроцессора.

Предполагая, что имя вашего файла равно foo.c

SOURCEFILE=foo.c
gcc -E -dI "$SOURCEFILE" | awk '
    /^# [0-9]* "/ { if ($3 == "\"'"$SOURCEFILE"'\"") show=1; else show=0; }
    { if(show) print; }'

или для подавления всех # line_number "file" строк для $SOURCEFILE:

SOURCEFILE=foo.c
gcc -E -dI "$SOURCEFILE" | awk '
    /^# [0-9]* "/ { ignore = 1; if ($3 == "\"'"$SOURCEFILE"'\"") show=1; else show=0; }
    { if(ignore) ignore=0; else if(show) print; }'

Примечание. Сценарии AWK не работают для имен файлов, содержащих пробелы.Чтобы обрабатывать имена файлов с пробелами, вы можете изменить скрипт AWK для сравнения $0 вместо $3.

0 голосов
/ 26 февраля 2019

Защита #include s от расширения, текстовый запуск препроцессора, удаление # 1 "<stdint>" и т. Д., Которые генерирует текстовый препроцессор, и повторное предоставление защищенных #include s.

Эта функция оболочки делает это:

expand_cpp(){
     sed 's|^\([ \t]*#[ \t]*include\)|magic_fjdsa9f8j932j9\1|' "$@" \
     | cpp | sed 's|^magic_fjdsa9f8j932j9||; /^# [0-9]/d'
}

до тех пор, пока вы держите слово включения вместе, вместо того, чтобы делать сумасшедшие вещи вроде

#i\
ncl\
u??/
de <iostream>

(выше вы можете видеть 2 строки продолжения с обратной косой чертой + 1 триграф (?? /== \) строка продолжения с обратной косой чертой).

При желании вы можете защитить #if s #ifdef s #ifndef s #endif s и #else s таким же образом.

Применительно к вашему примеру

example.c:

#include <stdio.h>
#define prn(s) printf("this is a macro for printing a string: %s\n", s);

int int(){
char str[5] = "test";
prn(str);
return 0;
}

, как с expand_cpp < example.c или expand_cpp example.c, генерирует:

#include <stdio.h>


int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);;
return 0;
}
0 голосов
/ 26 февраля 2019

Предположим, файл назван c.c:

gcc -E c.c | tail -n +`gcc -E c.c | grep -n -e "#*\"c.c\""  | tail -1 | awk -F: '{print $1}'`

Кажется, # <number> "c.c" отмечает строки после каждого #include

Конечно, вы также можете сохранить gcc -E c.c вфайл, чтобы не делать этого два раза

Преимущество в том, чтобы не изменять исходный код и не удалять #include перед тем, как выполнить gcc -E, который просто удаляет все строки извершина до последнего производится #include ... если я прав

0 голосов
/ 26 февраля 2019

Я согласен с замечанием Matteo Italia о том, что если вы просто запретите расширение директив #include, то результирующий код не будет отображать то, что на самом деле видит компилятор, и, следовательно, он будет иметь ограниченное применение при устранении неполадок.

Вот идея обойти это.Добавьте объявление переменной до и после ваших включений.Подойдет любая переменная, которая является достаточно уникальной.

int begin_includes_tag;
#include <stdio.h>
... other includes
int end_includes_tag;

Затем вы можете сделать:

> gcc -E main -o out.c | sed '/begin_includes_tag/,/end_includes_tag/d'

Команда sed удалит все, что находится между объявлениями переменных.

0 голосов
/ 26 февраля 2019

Когда расширение cpp включает в себя, оно добавляет # директивы ( linemarkers ) для отслеживания ошибок в исходных файлах.

Вы можете добавить шаг постобработки(его можно написать тривиально на любом языке сценариев или даже на C, если вам так хочется) для анализа только линейных маркеров и фильтрации строк, поступающих из файлов за пределами каталога вашего проекта;еще лучше то, что один из флагов (3) помечает системные заголовочные файлы (вещи, идущие по путям, указанным через -isystem, либо неявно драйвером компилятора, либо явно), так что это тоже можно использовать.

Например, в Python 3:

#!/usr/bin/env python3
import sys

skip = False
for l in sys.stdin:
    if not skip:
        sys.stdout.write(l)
    if l.startswith("# "):
        toks = l.strip().split(" ")
        linenum, filename = toks[1:3]
        flags = toks[3:]
        skip = "3" in flags

Использование gcc -E foo.c | ./filter.py Я получаю

# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "foo.c"
# 1 "/usr/include/stdio.h" 1 3 4



# 4 "foo.c"
int int(){
char str[5] = "test";
printf("this is a macro for printing a string: %s\n", str);;
return 0;
}
...