web-dev-qa-db-ja.com

コメントは通常どのように解析されますか?

コメントはプログラミング言語とマークアップで一般的にどのように扱われますか?私はいくつかのカスタムマークアップ言語のパーサーを作成していて、 最小の驚きの原則 に従いたいので、一般的な規則を決定しようとしています。

たとえば、トークン内に埋め込まれたコメントは、そのトークンを「妨害」するべきかどうか。一般的には次のようなものです:

Sys/* comment */tem.out.println()

有効ですか?

また、言語が新しい行に敏感で、コメントが新しい行にまたがっている場合、新しい行を考慮する必要があるかどうか。

stuff stuff /* this is comment
this is still comment */more stuff 

として扱われる

stuff stuff more stuff

または

stuff stuff
more stuff

私はいくつかの特定の言語が何をしているのかを知っています、私は意見を探していませんが、どうかを探しています:トークンと改行に関してマークアップによって一般に期待される一般的な合意はありますか?


私の特定のコンテキストは、wikiのようなマークアップです。

31
Sled

通常、コメントはトークン化プロセスの一部として、解析前にスキャン(および破棄)されます。コメントは、周囲に空白がない場合でもトークンセパレータのように機能します。

ご指摘のとおり、C仕様では、コメントは1つのスペースに置き換えられると明示的に規定されています。ただし、実際のパーサーは実際には何も置き換えず、空白文字をスキャンして破棄するのと同じ方法でコメントをスキャンして破棄するため、これは仕様に関する専門用語にすぎません。しかし、コメントはトークンがスペースと同じように分離されることを簡単な方法で説明しています。

コメントの内容は無視されるため、複数行コメント内の改行は無効です。改行に敏感な言語(PythonおよびVisual Basic)には通常複数行のコメントはありませんが、JavaScriptは例外です。例えば:

return /*
       */ 17

に相当

return 17

ない

return
17

単一行のコメントは改行を保持します。

return // single line comment
    17

に相当

return
17

ない

return 17

コメントはスキャンされますが解析されないため、ネストされない傾向があります。そう

 /*  /* nested comment */ */

コメントは最初の/*によって開かれ、最初の*/によって閉じられるため、構文エラーです

40
JacquesB

質問に答えるには:

マークアップによって一般に期待される一般的な合意はありますか?

トークンの中に埋め込まれたコメントが合法であるとは誰も期待しないでしょう。

一般的な経験則として、コメントは空白と同じように扱う必要があります。無関係な空白があるのに有効な場所には、コメントを埋め込むこともできます。唯一の例外は文字列です。

trace("Hello /*world*/") // should print Hello /*world*/

文字列内のコメントをサポートするのは非常に奇妙であり、それらをエスケープするのは面倒です!

9
Connor Clark

空白を区別しない言語では、無視された文字(つまり、空白またはコメントの一部である文字)がトークンを区切ります。

たとえば、_Sys tem_は2つのトークンですが、Systemは1つです。これの有用性は、new Foo()newFoo()を比較すると明らかになります。一方はFooのインスタンスを構築し、もう一方はnewFooを呼び出します。

コメントは、一連の空白文字と同じ役割を果たすことができます。 new/**/Foo()new Foo()と同じように機能します。もちろん、これはもっと複雑になる可能性があります。 new /**/ /**/ Foo()またはwhatnot。

技術的には、識別子内でコメントを許可することは可能であるはずですが、特に実用的ではないかと思います。

では、空白を区別する言語についてはどうでしょうか。

Pythonが頭に浮かび、非常に単純な答えがあります。ブロックコメントはありません。コメントを_#_で開始すると、パーサーは、行の残りの部分が存在せず、改行であるかのように機能します。

それとは対照的に、 jadeはブロックコメントを許可します 、同じインデントレベルに戻るとブロックは終了します。例:

_body
  //-
    As much text as you want
    can go here.
  p this is no longer part of the comment
_

したがって、この領域では、通常はがどのように処理されるかを言うことはできません。共通点のように見えるのは、コメントは常に行末で終了するということです。つまり、すべてのコメントは新しい行とまったく同じように機能します。

7
back2dos

過去に、私は語彙分析の​​一部としてコメントを単一のトークンに変えました。文字列についても同様です。そこから、人生は簡単です。

最後に作成したパーサーの特定のケースでは、エスケープルールが最上位の解析ルーチンに渡されます。エスケープルールは、コアグラマーにインラインでコメントトークンなどのトークンを処理するために使用されます。通常、これらのトークンは破棄されました。

この方法で行うことの結果は、識別子の真ん中にコメントを付けて投稿した例では、識別子は単一の識別子ではないことになります-これは、これまでに使用したすべての言語(メモリから)で予想される動作です。

文字列内のコメントのケースは、字句解析によって暗黙的に処理されます。文字列を処理するためのルールはコメントには関係がないため、コメントは文字列の内容として扱われます。コメント内の文字列(または引用符付きのリテラル)にも同じことが当てはまります。文字列はコメントの一部であり、明示的に単一のトークンです。コメントを処理するためのルールは文字列には関係ありません。

私はそれが理にかなっている/助けになることを願っています。

3
user202190

パーサーの目的によって異なります。コメントよりもコンパイル用の構文解析ツリーを構築するパーサーを作成する場合、トークンを分離する可能性のほかに意味的な値はありません(例:method/comment /(/ comment /))。この場合、スペースのように扱われます。

パーサーが1つのソース言語を別のソース言語に翻訳するトランスパイラーの一部である場合、またはパーサーがソース言語でコンパイルユニットを取得し、それを解析して変更し、同じソース言語で変更されたバージョンを書き戻すプリプロセッサである場合、コメント他のように非常に重要になります。

また、コメントにメタ情報があり、特にJavaDocのようにAPIドキュメントを生成するときのようにコメントに関心がある場合、コメントは突然非常に重要になります。

ここでは、コメントがトークン自体に添付されることがよくあります。コメントを見つけたら、それをトークンのコメントとして添付します。トークンは前後に複数のトークンを持つことができるため、これらのコメントの処理方法は目的に依存します。

コメントのないコメントトークンにコメントを付ける注釈の考え方は、文法からコメントを完全に削除することです。

パースツリーを作成したら、いくつかのASTが各トークンを表すコメントを独自のAST要素でアンパックし始めますが、通常の包含関係の横にある別のAST要素にアタッチされます。良いアイデアは、オープンソースIDEで利用可能なソース言語について、すべてのパーサー/ AST実装を確認してください。

非常に優れた実装の1つは、Java言語用のEclipseコンパイラインフラストラクチャです。これらは、トークン化中にコメントを保存し、AST内でコメントを表します-私が覚えている限り。また、このパーサー/ AST実装はフォーマットを保持します。

1
Martin Kersten