Удаление комментария C ++ из исходного кода - PullRequest
3 голосов
/ 10 декабря 2010

У меня есть код на C ++ с комментариями в стиле /* */ и //. Я хочу иметь способ удалить их все автоматически. Очевидно, что использование редактора (например, ultraedit) с некоторым регулярным выражением для поиска /*, */ и // должно сделать эту работу. Но, при ближайшем рассмотрении, полное решение не так просто, потому что последовательности / * или // могут не представлять комментарий, если они находятся внутри другого комментария, строкового литерала или символьного литерала. например,

printf(" \" \" " "  /* this is not a comment and is surrounded by an unknown number of double-quotes */");

- последовательность комментариев внутри двойной кавычки. И это не простая задача определить, находится ли строка внутри пары допустимых двойных кавычек. Пока это

// this is a single line comment /* <--- this does not start a comment block 
// this is a second comment line with an */ within

- последовательность комментариев внутри других комментариев.

Существует ли более полный способ удаления комментариев из источника C ++ с учетом строкового литерала и комментария? Например, можем ли мы дать указание препроцессору удалять комментарии, не выполняя, скажем, директиву #include?

Ответы [ 6 ]

3 голосов
/ 10 декабря 2010

Препроцессор C может удалять комментарии.

Отредактировано:

Я обновил, чтобы мы могли использовать MACROS для расширения операторов #if

> cat t.cpp
/*
 * Normal comment
 */
// this is a single line comment /* <--- this does not start a comment block 
// this is a second comment line with an */ within
#include <stdio.h>

#if __SIZEOF_LONG__ == 4
int bits = 32;
#else
int bits = 16;
#endif

int main()
{
    printf(" \" \" " " /* this is not a comment and is surrounded by an unknown number of double-quotes */");
    /*
     * comment with a single // line comment enbedded.
     */
    int x;
    // A single line comment /* Normal enbedded */ Comment
}

Поскольку мы хотим, чтобы операторы #if правильно расширялись, нам нужен список определений.
Это относительно тривиально.cpp -E -dM.

Затем мы передаем #defines и исходный файл обратно через препроцессор, но на этот раз не позволяем расширять включения.

> cpp -E -dM t.cpp > /tmp/def
> cat /tmp/def t.cpp | sed -e s/^#inc/-#inc/ | cpp - | sed s/^-#inc/#inc/
# 1 "t.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "t.cpp"






#include <stdio.h>


int bits = 32;




int main()
{
    printf(" \" \" " " /* this is not a comment and is surrounded by an unknown number of double-quotes */");    



    int x;

}
2 голосов
/ 10 декабря 2010

Наш SD C ++ Formatter имеет возможность довольно распечатать исходный текст и удалить все комментарии.Он использует наш полный интерфейс C ++ для синтаксического анализа текста, поэтому его не смущают пробелы, разрывы строк, строковые литералы или проблемы препроцессора, а также он не нарушает код при изменении форматирования.комментарии, вы можете пытаться запутать исходный код.Форматтер также поставляется в запутанной версии.

1 голос
/ 16 декабря 2010

Пусть кто-нибудь проголосует за мой собственный ответ на мой вопрос.

Благодаря идее Мартина Йорка я обнаружил, что в Visual Studio решение выглядит оченьпросто (подлежит дальнейшему тестированию).Просто переименуйте ВСЕ директивы препроцессора во что-то другое (что-то, что не является допустимым синтаксисом c ++, все в порядке) и используйте cl.exe с / P

cl target.cpp /P

, и он выдаст target.i.И это содержит источник минус комментарии.Просто переименуйте предыдущие директивы обратно, и все.Возможно, вам потребуется удалить директиву #line, сгенерированную cl.exe.

Это работает, потому что в соответствии с MSDN этапы перевода таковы:

Отображение символов Символы в исходном файле сопоставляются с внутренним исходным представлением.Последовательности триграфов на этом этапе преобразуются во внутреннее односимвольное представление.

Сращивание строк Все строки, заканчивающиеся обратной косой чертой () и сразу после символа новой строки объединяются со следующей строкой висходный файл, формирующий логические строки из физических строк.Если он не пуст, исходный файл должен заканчиваться символом новой строки, которому не предшествует обратная косая черта.

Токенизация Исходный файл разбивается на токены предварительной обработки и символы пробела.Комментарии в исходном файле заменяются одним пробелом каждый.Символы новой строки сохраняются.

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

Отображение набора символов Все члены исходного набора символов и escape-последовательности преобразуются в их эквиваленты при выполнении.набор символов.Для Microsoft C и C ++ исходный и исполняющий наборы символов являются ASCII.

Конкатенация строк Все литералы смежных строк и широких строк объединяются.Например, «Строка» «Конкатенация» становится «Строка Конкатенация».

Перевод Все токены анализируются синтаксически и семантически;эти токены преобразуются в объектный код.

Связь Все внешние ссылки разрешаются для создания исполняемой программы или библиотеки динамических ссылок

Комментарии удаляются во время Токенизация до Предварительная обработка фаза.Поэтому просто убедитесь, что на этапе предварительной обработки ничего не доступно для обработки (без удаления всех директив), и его выходные данные должны быть такими же, как обработанные предыдущими 3 фазами.

Что касается пользовательских .h файлов,используйте параметр / FI, чтобы включить их вручную.Результирующий файл .i будет представлять собой комбинацию .cpp и .h.без комментариев.Каждому фрагменту предшествует строка # с правильным именем файла.Так что их легко разделить по редактору.Если мы не хотим разбивать их вручную, возможно, нам нужно использовать средства макросов / сценариев некоторых редакторов, чтобы сделать это автоматически.

Итак, теперь нам не нужно заботиться одирективы препроцессора.Еще лучше то, что обрабатывается символ продолжения строки (обратная косая черта).

Например,

// vc8.cpp : Defines the entry point for the console application.
//

-#include "stdafx.h"
-#include <windows.h>
-#define NOERR
-#ifdef NOERR
  /* comment here */
 whatever error line is ok
-#else
  some error line if NOERR not defined
      // comment here
-#endif
void pr() ;
int _tmain(int argc, _TCHAR* argv[])
{
    pr();
    return 0;
}

/*comment*/

void pr() {
    printf(" /* "); /* comment inside string " */
    // comment terminated by \
    continue a comment line
    printf(" "); /** " " string inside comment */
    printf/* this is valid comment within line continuation */\
("some weird lines \
with line continuation");
}

После cl.exe vc8.cpp /P он становится этим, а затем может быть снова передан cl.exe после восстановлениядирективы (и удаление #line)

#line 1 "vc8.cpp"



-#include "stdafx.h"
-#include <windows.h>
-#define NOERR
-#ifdef NOERR

 whatever error line is ok
-#else
  some error line if NOERR not defined

-#endif
void pr() ;
int _tmain(int argc, _TCHAR* argv[])
{
    pr();
    return 0;
}



void pr() {
    printf(" /* "); 


    printf(" "); 
    printf\
("some weird lines \
with line continuation");
}
1 голос
/ 10 декабря 2010

Regex не предназначен для анализа языков, в лучшем случае это неудачная попытка.

Для этого вам действительно нужен полноценный парсер. Возможно, вы захотите рассмотреть Clang, переписывание является явной целью набора библиотек Clang, и уже существуют реализованные переписывающие устройства, от которых вы можете получить вдохновение.

1 голос
/ 10 декабря 2010

Вы можете использовать синтаксический анализатор на основе правил (например, boost :: spirit) для написания синтаксических правил для комментариев.Вам нужно будет решить, обрабатывать ли вложенные комментарии или нет, в зависимости от вашего компилятора.Семантические действия по удалению комментариев должны быть довольно простыми.

0 голосов
/ 08 июля 2017
#include <iostream>
#include<fstream>
using namespace std;

int main() {
    ifstream fin;
    ofstream fout;
    fin.open("input.txt");
    fout.open("output.txt");
    char ch;
    while(!fin.eof()){
        fin.get(ch);
        if(ch=='/'){
            fin.get(ch);
            if(ch=='/' )
            {   //cout<<"Detected\n";
                fin.get(ch);
                while(!(ch=='\n'||ch=='\0'))
                {
                //cout<<"while";
                fin.get(ch);
                }
            }
            if(ch=='*')
            {
                fin.get(ch);
                while(!(ch=='*')){
                    fin.get(ch);
                }
                fin.get(ch);
                if(ch=='/'){
                //  cout<<"Detected Multi-Line\n";
                    fin.get(ch);
                }

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