web-dev-qa-db-ja.com

JavaがCよりも解析しやすいのはなぜですか?

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

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

Cのコンテキスト依存性について私が見たすべての例は技術的には許容できるが、非常に奇妙だからです。例えば、

foo (a);

引数fooでvoid関数aを呼び出すこともできます。または、afoo型のオブジェクトとして宣言することもできますが、同じように簡単にパラメーターを削除できます。一部、この奇妙なことが起こるのは、 C grammar の「直接宣言子」生成規則が、関数と変数の両方を宣言するという二重の目的を満たすためです。

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

foo a;

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

TypedefのためにCは解析しにくいと言われましたが、Javaも。C文法規則、direct_declarator、障害がありますか?

89
korrok

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

これを参照してください C(およびC++)が解析するのが「難しい」理由を説明するSOの回答 。要約すると、CおよびC++文法は本質的にあいまいです。それらは複数の解析を提供し、mustコンテキストを使用してあいまいさを解決します。人々は、解析するときにあいまいさを解決する必要があると仮定するという間違いを犯します。そうではない、以下を参照してください。解析するときにあいまいさを解決することを主張する場合、パーサーはより複雑になり、構築するのがはるかに難しくなります。しかし、その複雑さは自傷です。

IIRC、Java 1.4の「明白な」LALR(1)文法は曖昧ではなかったので、解析が「簡単」でした。現代のJavaには少なくとも長距離の局所的な曖昧さがありません;「... >>」が2つのテンプレートを閉じるのか、それとも「右シフト演算子」であるのかを決定する問題が常にあります。 modern = JavaはLALR(1)で解析されなくなりました

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

しかし、解析は問題のある場所ではありません。

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

ほとんどの人は純粋な構文解析部分に苦労します(しばしば終わることはありません;実際の言語用に動作する構文解析ツールを構築する方法に関する多くの、多くの質問についてはSO自体を確認してください)そして、解析が困難なものについて民俗定理を取得し、その段階後に何が起こるかについてのシグナルはありません。

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

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

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

76
Ira Baxter