Анализ исходного файла C после предварительной обработки

#c #c #parsing

#c #c #синтаксический анализ

Вопрос:

Я пытаюсь проанализировать c файлы, используя свой пользовательский анализатор (написанный на c ). Перед началом синтаксического анализа я хотел бы избавиться от всего #define . Я хочу, чтобы исходный файл можно было компилировать после предварительной обработки. Таким образом, лучшим способом будет запуск C Preprocessor с файлом.

 cpp myfile.cpp temp.cpp
// or
g   -E myfile.cpp > templ.cpp
  

[Новые предложения приветствуются.]

Но из-за этого исходные строки и их номера строк будут потеряны, поскольку файл также будет содержать всю информацию заголовка, и я хочу сохранить номера строк. Итак, я решил, что выход,

  1. Добавьте специальный символ перед каждой строкой в исходном файле (кроме препроцессоров)
  2. Запустите препроцессор
  3. Извлеките строки с этим специальным символом и проанализируйте их

Например, типичный исходный файл будет выглядеть следующим образом:

 #include<iostream>
#include"xyz.h"
int x;    
#define SOME value
/*
**  This is a test file
*/
typedef char* cp;

void myFunc (int* i, ABC<int, X<double> > o)
{
  //...
}

class B {
};
  

После добавления символа это будет похоже,

 #include<iostream>
#include"xyz.h"
@3@int x;    
#define SOME value
@5@/*
@6@**  This is a test file
@7@*/
@8@typedef char* cp;
@9@
@10@void myFunc (int* i, ABC<int, X<double> > o)
@11@{
@12@  //...
@13@}
@14@
@15@class B {
@16@};
  

Как только все макросы и комментарии будут удалены, у меня останутся тысячи строк, в которых несколько сотен будут оригинальным исходным кодом.

Правильный ли этот подход? Я пропустил какой-либо угловой регистр?

Комментарии:

1. Чего вы пытаетесь достичь?

2. @Michael, я хочу избавиться от макросов (т.Е. #define ) из исходных файлов, прежде чем я начну анализировать их с помощью моего анализатора.

3. Я тоже не знаю, какова ваша конечная цель. В академических целях вы, возможно, захотите взглянуть на интерфейс Clang ( clang.llvm.org ), он имеет модульную конструкцию, и это то, что вы можете интегрировать в другие приложения / инструменты.

4. @Julio, Не для академических целей. Как только разбор будет завершен, я буду модифицировать исходный код определенным образом. Однако объяснять все будет слишком сложно для написания. Я надеюсь, что, по крайней мере, мой вопрос поясняющий. Пожалуйста, дайте мне знать, если я чего-то не понимаю.

5. @iammilind: Если это не для академических целей, я думаю, что пытаться написать свой собственный интерфейс C — это своего рода безумие. Множество вещей, таких как создание экземпляра шаблона и поиск в зависимости от аргумента, может быть чрезвычайно сложным для правильной реализации, и существует по крайней мере два отличных и свободно доступных интерфейса C , которые вы можете использовать ( g и LLVM clang ), на разработку каждого из которых уходят миллионы часов, и все еще часто содержат серьезные ошибки.

Ответ №1:

Вы понимаете, что g -E добавляет некоторые из своих собственных строк к своим выводам, которые указывают номера строк в исходном файле? Вы найдете строки, подобные

 # 2 "foo.cc" 2
  

это указывает на то, что вы просматриваете строку 2 файла foo.cc . Эти строки вставляются всякий раз, когда нарушается обычная последовательность строк.

Комментарии:

1. Я думаю, эти строки добавлены только для заголовков. Для общего кода это не так.

2. @iammilind: нет, они добавляются после каждого изменения файла. из него можно вывести фактические номера строк.

3. @Mat, но могу ли я извлечь исходный код исходного файла? Если я предварительно обработал «x.cpp «тогда меня интересует только анализ «x.cpp «исходный код. Как правило, они загромождены множеством других namespaces и function declarations , которые меня не интересуют.

4. @iammilind: после каждой # n "foo.cpp" x вы знаете, что следующие строки (до следующей # q "file.x" y ) из foo.cpp строка n и следующая. итак, да, вы все время точно знаете, где находитесь.

5. @Mat, ты прав. Это сэкономит мне много работы. Единственное, что я должен продолжать отслеживать для "foo.cpp" с помощью чисел n и x . В основном это отображается в начале и конце предварительно обработанного файла. Никогда не замечал этого должным образом.

Ответ №2:

imake Программа, которая раньше поставлялась с исходными текстами X11, использовала слегка похожую систему, помечая концы строк @@ , чтобы она могла правильно их обработать после.

Выходные данные из gcc -E обычно включают #line директивы; возможно, вы могли бы использовать их вместо своих символов.

Комментарии:

1. Интересно. Но я не хотел бы использовать # , поскольку он используется и в других местах. Правильный ли текущий подход, упомянутый в вопросе?

2. @iammilind: выходные данные GCC будут включать #line директивы, вероятно, в сокращенной форме без ключевого слова line , как упоминал Эрнест. Вы можете использовать @99@ для обозначения начала строк. Я привел исторический прецедент использования @@ ; по общему признанию, это было в конце строки, а не в начале, но @ символ — один из лучших вариантов (видимый и иначе не используемый C).