2

私が直面している問題は、Cスタイルのコメントを必要とするANSIコンパイラにあります。

そのため、既存のコメントをC標準ISOC89に準拠するように変換しようとしています。

//コメントが/** /コメント内に表示される場合を除いて//コメントを/*コメントに置き換えるSED式を探しています(コメントが壊れます)。

私はこれ(範囲式)を無駄に試しました:

sed -e '/\/*/,/*\//! s_//\(.*\)_/*\1 */_' > filename

このようなコメント内の1行のコメントを無視して、他のすべてを変更する何かが機能しますか?

/**********************************
* Some comment
* an example bit of code within the comment followed by a //comment
* some more comment
***********************************/
y = x+7; //this comment must be changed

ありがとう!

4

6 に答える 6

4

これは、必要な変換を実行するCで記述された簡単にテストされたフィルターです。このフィルターが何をするかについてのいくつかのコメントは、正規表現で処理することが不可能ではないにしても難しいです:

  • 引用符で囲まれたコメントのようなシーケンスは無視されます(コメントではないため)
  • 変換中のC99コメントにC89コメントを開始または終了するものが含まれている場合、そのシーケンスが変更されるため、ネストされたコメントやコメントの途中で終了することはありません(ネストされた、/*または*/に変更され/+ます/|)。これが必要かどうかはわかりませんでした(必要ない場合は、簡単に削除できるはずです)
  • 上記のネストされたコメントの変更は、変換中のC99コメントでのみ発生します。すでにC89スタイルになっているコメントの内容は変更されません。
  • トリグラフまたはダイグラフは処理しません(これにより、トリグラフで開始されるエスケープシーケンスまたは行末の継続が欠落する可能性があるだけだと思います??/)。

もちろん、目的に適しているかどうかを判断するには、独自のテストを実行する必要があります。

#include <stdio.h>

char* a = " this is /* a test of \" junk // embedded in a '\' string";
char* b = "it should be left alone//";

// comment /* that should ***////  be converted.
/* leave this alone*/// but fix this one

// and "leave these \' \" quotes in a comment alone*
/****  and these '\' too //
*/


enum states {
    state_normal,
    state_double_quote,
    state_single_quote,
    state_c89_comment,
    state_c99_comment
};

enum states current_state = state_normal;

void handle_char( char ch)
{
    static char last_ch = 0;

    switch (current_state) {
        case state_normal:
            if ((last_ch == '/') && (ch == '/')) {
                putchar( '*');  /* NOTE: changing to C89 style comment */
                current_state = state_c99_comment;
            }
            else if ((last_ch == '/') && (ch == '*')) {
                putchar( ch);
                current_state = state_c89_comment;
            }
            else if (ch == '\"') {
                putchar( ch);
                current_state = state_double_quote;
            }
            else if (ch == '\'') {
                putchar( ch);
                current_state = state_single_quote;
            }
            else {
                putchar( ch);
            }
            break;

        case state_double_quote:
            if ((last_ch == '\\') && (ch == '\\')) {
                /* we want to output this \\ escaped sequence, but we */
                /* don't want to 'remember' the current backslash -   */
                /* otherwise we'll mistakenly treat the next character*/
                /* as being escaped                                   */

                putchar( ch);
                ch = 0;
            }
            else if ((ch == '\"') && (last_ch != '\\')) {
                putchar( ch);
                current_state = state_normal;
            }
            else {
                putchar( ch);
            }
            break;

        case state_single_quote:
            if ((last_ch == '\\') && (ch == '\\')) {
                /* we want to output this \\ escaped sequence, but we */
                /* don't want to 'remember' the current backslash -   */
                /* otherwise we'll mistakenly treat the next character*/
                /* as being escaped                                   */

                putchar( ch);
                ch = 0;
            }
            else if ((ch == '\'') && (last_ch != '\\')) {
                putchar( ch);
                current_state = state_normal;
            }
            else {
                putchar( ch);
            }
            break;

        case state_c89_comment:
            if ((last_ch == '*') && (ch == '/')) {
                putchar( ch);
                ch = 0; /* 'forget' the slash so it doesn't affect a possible slash that immediately follows */
                current_state = state_normal;
            }
            else {
                putchar( ch);
            }
            break;

        case state_c99_comment:
            if ((last_ch == '/') && (ch == '*')) {
                /* we want to change any slash-star sequences inside */
                /* what was a C99 comment to something else to avoid */
                /* nested comments                                   */
                putchar( '+');
            }
            else if ((last_ch == '*') && (ch == '/')) {
                /* similarly for star-slash sequences inside */
                /* what was a C99 comment                    */
                putchar( '|');
            }
            else if (ch == '\n') {
                puts( "*/");
                current_state = state_normal;
            }
            else {
                putchar( ch);
            }
            break;
    }

    last_ch = ch;
}

int main(void)
{
    int c;

    while ((c = getchar()) != EOF) {
        handle_char( c);
    }

    return 0;
}

いくつかの贅沢な解説:何年も前に、私が働いていた店は、当時使用していたコンパイラに問題がなかったとしても、コードが必要になる可能性があるという理由で、C99スタイルのコメントを禁止するコーディング標準を課したいと考えていましたそれらをサポートしていないコンパイラに移植されました。私(および他の人)は、その可能性は本質的に存在しないほど遠いものであり、たとえそれが起こったとしても、コメントを互換性のあるものにするための変換ルーチンを簡単に書くことができると首尾よく主張しました。C99 /C++スタイルのコメントの使用が許可されました。

私は今、私の誓いが成就したと考えており、私にかけられたかもしれないどんな呪いも解き放たれると考えています。

于 2012-08-17T06:26:00.613 に答える
0

@ephemientの提案を使用できない場合は、複数の行に正規表現を適用する必要があります。これは、sedのデフォルトの動作ではありません。sedにはホールドバッファがあり、複数の文字列を一緒に追加して、連結された文字列に正規表現を適用できます。

sed式は次のようになります。

sed '1h;1!H;${;g;s/your-matcher-regex/replacement-regex/g;}'

1h-最初の行の場合は、その行をホールドバッファに入れます(最初に空にします)

1!H-最初の行でない場合は、ホールドバッファに追加します

$ {...}-最後の行の場合は、このsedコマンドを実行します

これで、/*と*/が異なる行にある場合でも、マッチャー式が機能します。

于 2012-08-17T05:13:14.030 に答える
0
awk '{if($0~/\/\//){sub(/\/\//,"\/\*");$0=$0"*/"};print}' temp
于 2012-08-17T05:35:38.193 に答える
0

/*さまざまなマークアップとコメントを出力できるコンバーターを使用してコードを色付きのHTMLに変換し//、perl / awk / sed / whateverで出力を処理してから、マークアップを削除します。

于 2012-08-17T06:37:02.330 に答える
0

これは(ほぼ)完全にsedで実行できます。必要なのは、次の1回の呼び出しだけですtr

translate_comments_prepare.sed

s/\\/\\\\/g  # escape current escape characters
s/\$/\\S/g   # write all occurrences of $ as \S
s/(/\\o/g    # replace open braces with \o
s/)/\\c/g    # replace closing braces with \c
s/$/$/       # add a $ sign to the end of each line
s_/\*_(_g    # replace the start of comments with (
s_\*/_)_g    # replace the end of comments with )

次に、「前処理」ステップの結果をパイプ処理して、tr -d '\n'すべての行を結合します(これを内部から行うための適切な方法がわかりませんsed)。

そして、実際の作業を行います。

translate_comments.sed

s_//\([^$]*\)\$_(\1)$_g  # replace all C++ style comments (even nested ones)
:b                       # while loop
                         # remove nested comment blocks:
                         #   (foo(bar)baz) --> (foobarbaz)
s/(\([^()]*\)(\([^()]*\))\([^()]*\))/(\1\2\3)/
tb                       # EOF loop
s_(_/*_g                 # reverse the steps done by the preparation phase
s_)_*/_g                 # ...
s/\$/\n/g                # split lines that were previously joined
s/\\S/$/g                # replace escaped special characters
s/\\o/(/g                # ...
s/\\c/)/g                # ...
s/\\\(.\)/\1/g           # ...

次に、基本的にすべてをまとめます

sed -f translate_comments_prepare.sed | tr -d '\n' | sed translate_comments.sed
于 2012-08-17T06:59:14.950 に答える
0

これはあなたのために働くかもしれません(GNU sed):

sed ':a;$!{N;ba};s/^/\x00/;tb;:b;s/\x00$//;t;s/\x00\(\/\*[^*]*\*\+\([^/*][^*]*\*\+\)*\/\)/\1\x00/;tb;s/\x00\/\/\([^\n]*\)/\/*\1\*\/\x00/;tb;s/\x00\(.\)/\1\x00/;tb' file

説明:

  • :a;$!{N;ba}ファイルをパターンスペースに丸呑みする
  • s/^/\x00/マーカーを設定しますNBこれはファイルにない任意の文字にすることができます
  • tb;:bプレースホルダーにジャンプして置換スイッチをリセットしますb
  • s/\x00$//;tマーカーがファイルの終わりに達しました。全部終わった。
  • s/\x00\(\/\*[^*]*\*\+\([^/*][^*]*\*\+\)*\/\)/\1\x00/;tbこの正規表現はcスタイルのコメントと一致し、trueの場合はマーカーがそれらを渡します。
  • s/\x00\/\/\([^\n]*\)/\/*\1\*\/\x00/;tbこの正規表現は1行のコメントと一致し、cスタイルのコメントに置き換えられ、trueの場合はマーカーがそれらを通過します。
  • s/\x00\(.\)/\1\x00/;tbこの正規表現は任意の1文字に一致し、trueの場合はマーカーが通過したものをバンプします。
于 2012-08-17T07:31:30.637 に答える