web-dev-qa-db-ja.com

flex / lexでcスタイルのコメントを取得するのが難しい

/ * * /のようなcスタイルのコメントを消費するようにflexでルールを作成したい

私は以下を持っています

c_comment "/*"[\n.]*"*/"

しかし、それは決して一致しません。理由は何ですか?私のコードがもっと必要な場合は、私に知らせてください。すべてを提出します。返信してくれた人に感謝します。

29
adhanlon

代わりに 開始条件 を使用することをお勧めします。

%x C_COMMENT

"/*"            { BEGIN(C_COMMENT); }
<C_COMMENT>"*/" { BEGIN(INITIAL); }
<C_COMMENT>\n   { }
<C_COMMENT>.    { }

<condition>とルールの間に空白があってはならないことに注意してください

%x C_COMMENTはC_COMMENT状態を定義し、ルール/*はそれを開始します。開始されると、*/は初期状態に戻り(INITIALは事前定義されています)、他のすべての文字は特別なアクションなしで消費されます。 2つのルールが一致する場合、Flexは最も長い一致を持つルールを取得することで明確にするため、ドットルールは*/の一致を妨げません。 ドットは改行以外のすべてに一致する であるため、\nルールが必要です。

%x定義により、C_COMMENTは排他状態になります。つまり、レクサーは、状態に入ると<C_COMMENT>に「タグ付けされた」ルールにのみ一致します。

これが 小さな例のレクサー で、/* comments */内のものを除くすべてを出力することでこの回答を実装します。

41
zneak

Zneakの答えを操作する方法について誰かが混乱している場合に備えて、次の例を示します。

(基本的に、彼の役立つリンクで説明されているように、最初のセクションに「%x C_COMMENT」を配置し、残りを2番目のセクションに配置します)

foo.l

%{
// c code..
%}
%x C_COMMENT

%%
"/*"            { BEGIN(C_COMMENT); }
<C_COMMENT>"*/" { BEGIN(INITIAL); }
<C_COMMENT>.    { }

%%
// c code..

それが誰かを助けることを願っています!ティフ

9
user1747935

なぜそれが取り上げられないのかはわかりませんが、そのようなパターンが大きな語彙要素を生成する可能性があることは知っています。開始コメントマーカーだけを検出し、終了マーカーが見つかるまでビットバケット内のすべてを投げる方が効率的です。

このサイト それを行うコードがあります:

"/*" {
    for (;;) {
        while ((c = input()) != '*' && c != EOF)
            ; /* eat up text of comment */
        if (c == '*') {
            while ((c = input()) == '*')
                ;
            if (c == '/')
                break; /* found the end */
        }
        if (c == EOF) {
            error ("EOF in comment");
            break;
        }
    }
}
7
paxdiablo

この解決策はもっと簡単だと思います。

"/*"((\*+[^/*])|([^*]))*\**"*/"
2
Mugen

Flexマニュアル に実際の例があります。これは、厄介なEdgeケースを正しく取得します。

<INITIAL>"/*"         BEGIN(IN_COMMENT);
<IN_COMMENT>"*/"      BEGIN(INITIAL);
<IN_COMMENT>[^*\n]+   // eat comment in chunks
<IN_COMMENT>"*"       // eat the lone star
<IN_COMMENT>\n        yylineno++;
1
David Given

私は提案された解決策のいくつかを試しました、そしてここに結果があります。

  • 賛成票が最も多く、見栄えの良いC_COMMENTソリューションを実際に機能させることができませんでした(コメントの1つで、少なくとも1つの理由が説明されています)。それは反対票を投じるべきであり、確かに最高票の解決策であってはなりません
  • Mugenのソリューションは、実行したすべてのコードで機能するようでした
  • AndreyからLexでコンパイルするためのソリューションを取得できませんでした。参照されているウェブサイトを見て、そこからパターンを使用しても役に立ちませんでした
  • paxdiabloからの回答は機能し、読みやすいという利点がありました。私はさらに次のように変更しました:

     "/ *" {int c1 = 0、c2 = input(); 
     for(;;){
     if(c2 == EOF)break; 
     if(c1 == '*' && c2 == '/')
     break; 
     c1 = c2; 
     c2 = input(); 
    } 
    } 
    
1
mwag

実施例は次のとおりです。

\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\/

ostermiller.org で見つかりました

0
Andrey