3

ソース ファイルからすべての関数/列挙型/構造体/etc の名前を持つファイルを作成しようとしています。そのために、私は現在、次のsedようなことを達成するために使用しようとしています:

(元のファイル)

function add1 (int i) {
    return i+1;
}

(sedの出力)

function add1 (int i) {
}

つまり、関数本体の実際の内容を削除したいのです。私はこれまでそれを機能させることができませんでした。助言がありますか?

編集:私はこのようなことを試みましたが、成功しませんでした(今のところ、関数の本体の行のみを空白にしようとしています):

sed '/{/,/}/ s/.*//'
4

3 に答える 3

4

一貫してフォーマットされたファイルでは、次のようなことができます

sed '/{$/ {:r;/\n}/!{N;br}; s/\n.*\n/\n/}'

関数本体を一度に読み取り、中かっこ内のすべてを削除します。

$ echo 'function add1 (int i) {
    if (i == 1) {return i+1;}
}' | sed '/{$/ {:r;/\n}/!{N;br}; s/\n.*\n/\n/}'
function add1 (int i) {
}

{このコマンドは、改行の直前で始まり}改行の直後で終わるブロックでのみ機能します。

この:r;/\n}/!{N;br}部分では、入力からパターンスペースに別の行が追加されたという名前のラベル:rを定義し( )、実行フローが再び先頭に移動します ( )。に遭遇するまで発生します。したがって、その「ループ」から抜け出すと、関数本体全体がパターン空間にあり、コマンドが適用されます。rNrbr\n}s

于 2012-09-23T09:50:06.977 に答える
1

の代わりに、文字フィールドごとのモード ( )でsedいつでも使用できます。awkFS=""

awk 'BEGIN {
         RS = "\n" ;
         FS = "" ;
         d = 0 ;
     }

     {
         for (i=1; i<=NF; i++)
             if ($i == "{") {
                 d++ ;
                 if (d == 1) printf "{\n"
             } else
             if ($i == "}") {
                 d-- ;
                 if (d == 0) printf "}"
             } else
             if (d == 0)
                 printf "%s", $i ;
         if (d == 0) printf "\n"
     }' INPUT-FILE(s)...

上記は、ペアの中括弧の内容、つまり関数と構造体の本体、配列の初期化などをスキップし、結果を標準出力に出力します。1 つ以上のファイルを指定できます。(ファイルを指定しない場合、標準入力からの入力が期待されます。)

現在のように、引用符やコメント内のブレースについて混乱するでしょう。これは同じ方法で修正できますが、かなり複雑になります。これは、ほとんどの方法を取得するための単なるハックです。

セミコロン ( ) を追加した;ので、上記のスニペットのすべてを 1 つの長いコマンド ラインに詰め込むことができます。

スクリプトのロジックは非常に単純です。FS入力のすべての文字が独自のフィールドになるように、空のフィールドセパレーター ( ) を使用します。ルールは、BEGIN入力が処理される前に 1 回実行され、これを設定します。開発者向けの情報として、d = 0必要に応じて初期化されていない変数が空またはゼロであると想定しているため、awk では必要ありませんが、初期化も行います。各入力文字の現在のブレースの深さを追跡します。

2 番目の中かっこで囲まれた式は、すべてのレコードごとに 1 回実行されます。を設定したのでRS = "\n"、各行は個別の式になります。したがって、入力行ごとに 1 回実行されます。によりFS = ""、その行の各文字は個別のフィールドになります。NFレコードには$1、 、$2、 ..、$(NF-1)、およびのフィールドがあります$NF。3 部構成の if 句は、単に最も外側の中かっこを出力し、中かっこ内にないすべてのもの (つまり when d == 0) を出力します。

このawkスクリプトレットを拡張して、コメント、文字列、文字定数 (\047単一引用符を参照するために使用します。スクリプトを で別のファイルに入れる場合を除きます#!/usr/bin/awk -f) を含めたり、プリプロセッサ マクロを処理または無視したりできます。

少し複雑になり、数百行の awk スクリプトが必要になりますが、信頼性が高く、適度に高速であるはずです。これが可能な理由は、この特定のケースでの C のトークン化規則に従うのが簡単だからです。個人的には、他のすべてのユース ケースでは本格的な C lexer (語彙アナライザーまたはスキャナー) を使用します。そしておそらくこれも。

本格的な C 字句解析器を使用したい場合は、ネット上で自由に利用できるものが多数ありますが、C や C++ などのより高度な言語を使用する必要があります。すべてのコーナー ケースを処理したい場合は、C/C++ プリプロセッサも組み込む必要がありますが、これらのルールは簡単です (awk を使用しても)。

于 2012-09-23T11:19:24.253 に答える
0

まず、C ソース ファイルが適切にインデントされていることを確認することをお勧めします。そのために使用できますindent -gnu

sed次に、いくつかのトリックを使用できます。適切にインデントされたコードでは、行の最初の文字として中かっこ (開始または終了) を気にするだけで済みます。

なぜあなたがそれをしたいのか、私にはわかりません。特に、struct入れ子にすることができ、実際に入れ子になっている場合もあります。また、病的なケースもあります。たとえば、プリプロセッサ マクロが中括弧を使用して定義する場合などです。

#includeより良い方法は、コンパイラの内部を操作することです (ただし、 -d ヘッダーから来るものを処理する必要があります)。その目的でMELTを使用できます(MELT は GCC を拡張するための高レベルのドメイン固有言語であり、GCC の内部に取り組んでいます)。

于 2012-09-23T09:59:26.057 に答える