JavaをCよりも解析しやすくするものは何ですか?


90

CとC ++の文法はコンテキスト依存であり、特にCで「レクサーハック」が必要であるという事実を知っています。一方、Javaのみを解析できるという印象を受けました2つの言語間のかなりの類似性にもかかわらず、先読みの2つのトークン。

解析しやすくするために、Cについて何を変更する必要がありますか?

私がCの状況依存性を見た例はすべて技術的には許容できるが、ひどく奇妙なので、私は尋ねます。例えば、

foo (a);

foo引数付きのvoid関数を呼び出している可能性がありますa。または、それaはタイプのオブジェクトであると宣言することfooもできますが、同様に簡単に括弧を取り除くことができます。この奇妙さは、C文法の「直接宣言子」生成規則が関数と変数の両方を宣言するという二重の目的を満たすために発生します。

一方、Java文法では、変数宣言と関数宣言に別々の生成規則があります。あなたが書くなら

foo a;

すると、それが変数宣言でありfoo、型名として明確に解析できることがわかります。foo現在のスコープのどこかにクラスが定義されていない場合、これは有効なコードではない可能性がありますが、これは、後のコンパイラパスで実行できるセマンティック分析の仕事です。

typedefのためにCは解析が難しいと言われているのを見てきましたが、Javaでも独自の型を宣言できます。に加えてdirect_declarator、どのC文法規則に誤りがありますか?


7
クールな質問。おそらくあまりにも広すぎるか、主に意見が分かれています。
アステリ2014年

37
これはパーサーについての有効な質問であり、それに関する幅広いまたは意見に基づく唯一のことは、最後の数文です(おそらく削除または変更する必要があります)。近い投票で終了します。
R .. GitHub ICEのヘルプの停止2014

1
私はそれに応じて質問を編集しました。@ R ..フィードバックに感謝します。
korrok 2014年

3
事実上すべての(標準)コンピュータ言語は状況依存です。1つの型の変数を宣言することはできず、ほとんどの言語でそれを誤用します。これは、「言語のすべての文法」が状況依存であるのとは異なります。パーサーを作成するほとんどの人は、コンテキストフリー(またはさらに制限された)パーサーを作成し、パーサーの外でハックを使用してコンテキストフリーのプロパティをチェックします。
Ira Baxter

1
@IraBaxter私はそれを「ハック」とは呼びません。状況依存言語の解析は効率的に実行できないため(そして実際、文脈自由言語の解析でさえ効率的ではないため、問題を2つに分割することは妥当なことのようです。そのため、一般的に文脈自由言語のサブセットに制限します) 。ASTを介してコンテキスト依存プロパティのみをチェックするコンテキストフリーの解析+静的分析は、妥当なことです。
Bakuriu 2014年

回答:


76

C ++の解析は難しくなっています。Javaの解析も同様に困難になっています。

C(およびC ++)が解析が「難しい」理由については、このSOの回答を参照してください。要約すると、CおよびC ++の文法は本質的にあいまいです。それらは複数の解析を提供し、あいまいさを解決するにはコンテキストを使用する必要あります。そうすると、解析の際に曖昧さを解決しなければならないと思い込んでしまいます。そうでない場合は、以下を参照してください。解析時にあいまいさを解決することを主張すると、パーサーはより複雑になり、構築がはるかに難しくなります。しかし、その複雑さは自傷行為です。

IIRC、Java 1.4の「明白な」LALR(1)文法はあいまいではなかったため、解析が「簡単」でした。私は、現代のJavaが少なくとも長距離のローカルな曖昧さを持っていないかどうかはわかりません。"... >>"が2つのテンプレートを閉じるのか、それとも "右シフト演算子"なのかを決定する問題が常にあります。私は現代のJavaがLALR(1)でもう解析しないのではないかと思います

しかし、どちらの言語でも、強力なパーサー(または、CとC ++のフロントエンドが現在主に行っているような弱いパーサーとコンテキストコレクションハック)を使用することで、解析の問題を回避できます。CとC ++には、プリプロセッサを使用するという複雑な問題があります。これらは実際には見た目よりも複雑です。1つの主張は、CおよびC ++パーサーは非常に難しいため、手動で作成する必要があるということです。 それは真実ではありません。GLRパーサージェネレーターでJavaおよびC ++パーサーを問題なく構築できます。

しかし、解析は実際には問題ではありません。

解析したら、AST /解析ツリーで何かをしたいと思うでしょう。実際には、すべての識別子について、その定義とその使用場所( "名前と型の解決"、だらしなく、シンボルテーブルの作成)を知る必要があります。これは、継承、インターフェース、オーバーロード、およびテンプレートによって複合されたパーサーを正しく取得するよりもはるかに多くの作業であることがわかります言語標準の。ここでC ++は本当に悪いです。この点から見ると、Java 7と8はかなりひどいものになっています。(そして、シンボルテーブルはあなたが必要とするすべてではありません。「解析後のライフ」についてのより長いエッセイについては私の略歴を参照してください)。

ほとんどの人は純粋な解析部分に苦労しています(多くの場合、決して終了しない。実際の言語に対応するパーサーを構築する方法についての多くの質問についてSO自体を確認してください)。そして、解析が難しいものについての民俗定理が得られ、その段階の後に何が起こるかについてのシグナルはありません。

C ++構文を修正してもどこにも行けません。

C ++構文の変更に関して:多くの場所にパッチを適用して、C ++文法のさまざまなローカルおよび実際のあいまいさを処理する必要があることがわかります。あなたが主張するならば、以下のリストは良い出発点かもしれません。あなたがC ++標準委員会でないなら、これを行う意味がないと私は思います。あなたがそうし、それを使ってコンパイラを構築したとしても、誰もそれを使うことはありません。既存のC ++アプリケーションへの投資が多すぎて、パーサーを作成する人たちの便宜のために切り替えることができません。さらに、彼らの苦痛は終わり、既存のパーサーは正常に動作します。

独自のパーサーを作成することもできます。OK、それは大丈夫です; コミュニティの残りの部分が、あなたが使いやすくするために使用する必要がある言語を変更できると期待しないでください。彼らは皆、彼らにとってより簡単であることを望んでおり、それは文書化され実装された言語を使用することです。


いい答えだ。これらの問題のいくつかを解決しようとするDおよびC +も参照してください。s / content /
contend

3
私は以前にLife After Parsingを読んだことがあり、それが本当の目を見張るものであることがわかりました。構文解析よりも意味解析(名前/型の解決など)の方がはるかに多くの作業があることが明らかになりました。言語の構文を変更するつもりはありません。私はないプロパティは、あなたが最初の構文解析を行うことが可能な言語、その後、意味解析であるかを理解したいと思います。Cはそのような言語ではありません(lexerハックが必要です)。私は常にJavaがそうであると思っていました。その理由を知りたいのです。
korrok 2014年

1
@Korrok:GLRパーサーを使用したJava / C ++の構築に関する私の答えを読んでください。 レクサーハックは必要ありません。したがって、その違いは、間違った解析テクノロジーを使用している人々の心にあります。...確かに、完全なC ++フロントエンド(特にC ++ 14、私たちが行った)を構築することは、Java8を実行することよりも困難ですが、どちらも(労力と詳細への注意の観点から)困難であり、解析も困難です。最も簡単な作品です。
Ira Baxter

1
「解析後のライフ」について同意します。たとえば、C#でのオーバーロードの解決は、3-SATの問題をエンコードできるため、NP困難です。
イェルクWミッターク

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.