10

あまりにもつまらないと思われる質問をするリスクを冒して、私は長い間、(さまざまなコンテキストで標準全体で発生する何かの1つの例として)integer literal§2.14.2の次の定義を正当化しようと努めてきました。 C ++ 11標準、特に1つの詳細に関しては、構文表記自体に空白が存在します。

(この例(整数リテラルの定義)は私の質問のポイントではないことに注意してください。私の質問のポイントは、特に文法範疇名の間の空白に関して、 C++標準自体で使用される構文記述表記について質問することです。ここで紹介する例(整数リテラルの定義)は、単純で明確な例として機能するという理由だけで特に選択されています。)

(簡潔にするために§2.14.2から省略):

integer-literal:
    decimal-literal integer-suffix_opt

decimal-literal:
    nonzero-digit
    decimal-literal digit

(予想通りnonzero-digitdigit[0] 1 ... 9)。(注:上記のテキストはすべて、標準ではイタリック体です。)

decimal-literalこれはすべて、構文カテゴリ記述間のスペースが実際のソースコードには存在しないと理解されていると仮定すると、私には理にかなっていますdigitが、セクション§2.14.2に示されているように構文記述自体にのみ存在します。

この規則(ソースコードにスペースが存在しないことが理解される場合に、表記内のカテゴリ記述の間にスペースを配置する)は、仕様の他の場所で使用されます。ここでの例は、スペースがソースコードに存在しないことが明らかに想定されている明確なケースです。(これらのカテゴリ記述がソースコード内の実際のトークンに置き換えられた場合、空白または他のセパレータが存在する必要がある、またはカテゴリ記述間にオプションである標準の反例については、この質問の反例を参照してください。)

繰り返しになりますが、気まぐれになるリスクがありますが、この例のように表記を解釈するときに、ソースコードにスペースを含めないという規則のステートメントを標準のどこにも見つけることができません。

この規格では、§1.6.1(およびそれ以降)の表記規則について説明しています。これに関して私が見つけることができる唯一の関連するテキストは次のとおりです。

この国際規格で使用されている構文表記では、構文カテゴリはイタリック体で示され、リテラルの単語と文字は一定幅のタイプで示されます。選択肢の長いセットが「の1つ」というフレーズでマークされているいくつかの場合を除いて、選択肢は別々の行にリストされています。</ p>

私はそんなにつまらないとは思わないでしょう。ただし、標準内で使用されている表記法はやや扱いにくいので、すべての詳細を明確にしたいと思います。時間を割いて私にこれを記入してくれる人に感謝します。

補遺「最終的なソースコードに空白を含めるべきではないことは明らかであるため、標準でこれを明示的に述べる必要はない 」と同様の主張がなされたコメントに応えて、私はこの質問で簡単な例を選択しました、それ明らかな場合。標準では、がないと明らかでない場合が多くあります。「const」と「volatile」について議論する§8.0.4などの言語の事前知識(私の意見では):

cv-qualifier-seq:
    cv-qualifier cv-qualifier-seq_opt

...ここでは反対の仮定に注意してください(最終的なソースコードでは空白、または別の区切り文字が必要です)が、構文表記自体から推測することはできません。

次のように、スペースがオプションの場合もあります。

noptr-abstract-declarator:
    noptr-abstract-declarator_opt parameters-and-qualifiers

(この例では、要点を説明するために、議論されているセクション番号や言い換えは示しません。文法表記自体から、このコンテキストでは、最終的なソースコードの空白が明らかかどうかを尋ねます。トークン間のオプションです。)

これらの線に沿ったコメント-「それは明白なので、それがなければならない」-は、私が選択した例が非常に明白であるという事実の結果であると思います。それがまさに私が例を選んだ理由です。

4

4 に答える 4

8

§2.7.1

トークンには、識別子、キーワード、リテラル、演算子、その他の区切り文字の5種類があります。以下で説明するように、空白、水平タブと垂直タブ、改行、フォームフィード、およびコメント(総称して「空白」)は、トークンを区切る場合を除いて無視されます。

したがって、リテラルがトークンであり、空白がトークンを区切るのに役立つ場合、リテラルの数字の間のスペースは2つの別個のトークンとして解釈されるため、同じリテラルの一部にすることはできません。

于 2012-12-07T00:08:20.003 に答える
6

私は、この事実の直接的な説明が規格にこれ以上ないことを合理的に確信しています。

使用される表記法は、一般的なBNFと十分に類似しているため、表記法の空白はBNF自体のトークンを分離する以外に重要ではないという事実を含め、同じ一般的な規則の多くを当然のことと見なします。トークンを区切る以外のソースコードには、トークンを直接指定するための表記が含まれます(たとえば、ほとんどの前処理ディレクティブでは、new-lineは直接指定されます。

#ifdef識別子改行グループopt

また:

#include <h-char-sequence> new-line

その責任はおそらくAlgol68標準にまでさかのぼります。これは、構文を正確に指定する試みでこれまでのところ行き過ぎており、数週間のフルタイムの研究なしでは誰も読むことが本質的に不可能でした1。それ以来、構文記述言語の最も大雑把な説明以上のものは、Algol 68に非常に似ているという理由で拒否につながり、形式的すぎて誰もそれを読んだり理解したりしないため、間違いなく失敗します。


1あなたが尋ねるのはどうしてそんなに悪いことでしょうか?それは基本的に次のようになりました:彼らは構文記述言語の正式な英語の記述から始めました。ただし、これはAlgol 68の定義には使用されませんでした。これは、別の構文記述言語を(さらに正確に)指定するために使用されました。次に、その2番目の構文記述言語を使用して、Algol68自体の構文を指定しました。したがって、 Algol 68構文自体を読み始める前に、2つの別々の構文記述言語を学ぶ必要がありました。間違いなく推測できるように、ほとんど誰もしませんでした。

于 2012-12-07T05:30:46.173 に答える
3

あなたが言うように、標準は言う:

定幅型のリテラル単語と文字

したがって、リテラルスペースをルールに含める場合は、一定幅タイプでレンダリングする必要があります。規格を詳しく調べると、参照しているプロダクションのスペースが定幅タイプよりも狭いことがわかります。(また、標準を引用しようとすると、イタリックでレンダリングする必要のあるものが一定幅タイプでレンダリングされ、結果として意味が変化するため、誤った表現になります。)


わかりました、それは「意欲的な言語弁護士」の答えでした。さらに、次の形式のすべてのプロダクションで失敗するため、実際には機能しません。

One of:
0 1 2 3 4 5 6 7 8 9

実際には、空白は正式な文法の一部ではないというのが答えだと思います。空白はトークンを区切るためだけに機能するからです。さらに、そのステートメントは、プログラムのインデントとは異なり、文法のインデントが重要であることを除いて、その空白がトークンではなく、トークンが空白で区切られている文法自体にほとんど当てはまります。


補遺に答えるための補遺

それは実際には真実ではなく、空白で区切る必要がありますconstvolatileそれらは単に別々のトークンである必要があります。例:

#define A(x)x
A(const)A(volatile)A(int)A(x)A(;)

繰り返しになりますが、より深刻なことに、第2章(特に2.2と2.5を参照していますが、テキスト全体を読む必要があります)では、トークンのストリームを生成するためにプログラムテキストがどのように処理されるかについて説明します。空白を無視する必要があると主張するすべての規則は文法のこの部分にあり、空白が必要である可能性があると主張するすべての規則はそうではありません。

これらは実際には2つの別個の文法ですが、適用するにはプリプロセッサの動作を考慮する必要があるため、字句文法は必然的に不完全です。

私が言ったことはすべて、標準から収集できると思います。ここにいくつかの抜粋があります:

2.2(3)ソースファイルは前処理トークン(2.5)と空白文字のシーケンス(コメントを含む)に分解されます…ソースファイルの文字を前処理トークンに分割するプロセスはコンテキストに依存します。

…</p>

2.2(7)トークンを区切る空白文字は重要ではなくなりました。各前処理トークンはトークンに変換されます。(2.7)。結果のトークンは、構文的および意味的に分析され、変換単位として変換されます。

これにより、2つの文法があることが明らかになると思います。1つは語彙素(つまり、一連の書記素(文字)から語彙素(トークン)を生成します)、もう1つは構文(つまり、一連の語彙素(トークン)からの抽象構文木。どちらの場合も(小さな例外を除いて、すぐにわかります)、字句文法で許可されている場合、空白は2つの語彙素が互いにぶつかるのを防ぐもの以外のものと見なされます。(2.5(3)のアルゴリズムを参照してください。)

C++構文的にきれいではないので、ほとんどの場合例外があります。から継承されたこれらの1つは、次Cの違いです。

#define A(X)(X)

#define A (X)(X)

前処理ディレクティブには独自の解析ルールがあり、これは次の定義に代表されます。

lparen:直前に空白がない
  文字(

これは、ルールを証明する例外です[注1]。(これの前に空白がないことを言う必要があるという事実は(、構文規則でのトークンの通常の使用がその空白空間のコンテキストについて何も述べていないことを示しています。

したがって、レイ・カミングス(時々主張されるようにアルバート・アインシュタインではない)を言い換えると、「時間と空白はすべて、あるトークンを別のトークンから分離します」。【注2】


[注1]ここでは、Ciceroのように、本来の法的な意味でこのフレーズを使用しています。

【注2】:

「時間」とジョージは言いました。「なぜ私はあなたに時間の定義を与えることができます。それはすべてが一度に起こるのを防ぐものです。」

笑いの波紋は、男性の小さなグループについて起こりました。

「かなりそうだ」と化学者は同意した。「そして、紳士、それは思ったほど面白くありません。実際のところ、それは実際には悪い科学的定義ではありません。時間と空間はすべて、あるイベントを別のイベントから分離しています…</ p>

-時間をマスターした男から、レイ・カミングス、1929年、エース・ブックス。Googleブックスの最初のページを参照してください

于 2012-12-07T06:28:45.610 に答える
3

標準には、実際には2つの別個の文法があります。

セクション2および16で説明されているプリプロセッサ文法は、変換フェーズ1〜6で、ソース文字のシーケンスが前処理トークンおよび空白文字のシーケンスに変換される方法を定義します。これらのフェーズの一部とこの文法の一部では、空白が重要です。

前処理トークンの一部ではない空白文字は、変換フェーズ4の後で重要でなくなります。標準では、変換フェーズ7の開始時に、前処理トークン間の空白文字を破棄するように明示的に指示されています。

言語文法は、一連のトークン(前処理トークンから変換されたもの)が翻訳フェーズ7で構文的および意味的にどのように解釈されるかを定義します。この文法には空白などはありません。(この時点で、' '文字通りです-文字通り'c'です。)

どちらの文法でも、標準に表示される文法コンポーネント間のスペースは、ソースまたは実行の空白文字とは関係ありません。標準を読みやすくするためだけにあります。プリプロセッサの文法が空白に依存している場合、次のように単語で綴ります。

c-char

一重引用符'、円記号\、または改行文字を除くソース文字セットのすべてのメンバー

エスケープシーケンス

ユニバーサル文字名

コントロールライン

..。

# define 識別子lparen識別子リスト[opt]) 置換リスト改行

..。

lparen

(空白が直前にない文字

したがって、プリプロセッサの文法では空白が許可されていないため、整数リテラルの数字の間に空白がない場合があります。

ここでのもう1つの重要なルールは、C ++112.5p3からのものです。

入力ストリームが特定の文字までの前処理トークンに解析されている場合:

  • 次の文字が、のような生の文字列リテラルのプレフィックスと最初の二重引用符である可能性のある文字のシーケンスを開始する場合、R"次の前処理トークンは生の文字列リテラルでなければなりません。..。

  • それ以外の場合、次の3文字が<::であり、後続の文字がどちら:でもない>場合、<はそれ自体でプリプロセッサトークンとして扱われ、代替トークンの最初の文字としては扱われません<:

  • それ以外の場合、次の前処理トークンは、それ以上の字句解析が失敗する原因になる場合でも、前処理トークンを構成する可能性のある文字の最長シーケンスです。

constしたがって、とトークンの間には空白が必要volatileです。そうしないと、トークンの可能な最長のルールがそれを単一の識別子トークンに変換するためconstvolatileです。

于 2012-12-07T19:09:28.590 に答える