2

学生の研究プロジェクトをしているときに問題が発生しました。私は電気工学の学生ですが、私のプロジェクトは理論計算機科学とある程度関係があります。タイプ定義と定数について多くのパスカルソースコードファイルを解析し、すべての発生を視覚化する必要があります。タイプ定義はさまざまなファイルに再帰的に分散されます。つまり、ファイルxにはタイプa =バイトがあり、ファイルyにはタイプaを含むレコード(構造体)bがあり、ファイルzにはタイプcもあります。タイプbの配列。これまでの私の考えは、コンパイラーがすべての型定義を解決し、それらを要素型に分解する必要があるため、コンパイラーの構築について学ぶことでした。

ですから、コンパイラの構築については2冊の本(そのうちの1冊はパスカルの発明者によって書かれています)で読んだことがありますが、理論計算機科学の基礎があまりにも不足しているため、途中で1週間だけで作業できました。 。これまでに学んだことは、私の目標を達成するには、レクサーとパーサーで十分なはずだということです。このソフトウェアはプロジェクト全体の中で本当に賢い部分にすぎないので、あまり時間をかけることができないので、flexを試し始め、後でantlrを試しました。

私の望みは、typedefinitionsのみの解析が非常に簡単な作業であり、スキャナーを使用するだけでそれを実行し、パーサーの作業を実行できるようにすることでした。pascalファイルは5つの主要部分で構成され、それぞれがオプションです。 :コメント付きのヘッダー、const-section、type-section、var-section、および(少なくとも場合は)code-section。各セクションには開始識別子がありますが、明確な終了識別子はありません。そこで、type-およびconst-section(TYPE、CONST)の先頭を検索し始め、それ以外はすべて破棄しました。フレックスでは、「開始条件」が可能になるため、これはかなり簡単です。これらは、「INITIAL」、「TYPE-SECTION」、「CONST-SECTION」、「COMMENT」などのさまざまな状態として使用でき、状態ごとに異なるルールがあります。次の構文"="でスキャナーから文字列を取得したかったのです。AuEingangsBool_t {PCMON} = MAX_AuEingangsFeld;。スキャナーは、正規表現でそのような型定義を抽出することはできません。

次のステップはスキャナーとパーサーで正しく行うことだったので、パーサジェネレーターを検索してantlrを見つけました。とにかくツールをC#で記述しているので、異なるプログラム間で通信する必要がないように、スキャナージェネレーターも使用することにしました。今、私は次の問題に遭遇しました:AFAIK、antlrはflexがサポートするように「開始条件」をサポートしていません。つまり、ファイル全体をスキャンして(大丈夫、コメントはまだ破棄されます)、不要な(そして間違った)トークンをたくさん取得する必要があります。パスカル文法全体にルールを使用しないため、スキャナーはパスカル構文のほとんどのキーワードをユーザーIDとして識別し、パーサーは型定義と定数定義に適合しない一連のトークンすべてについてナグします。

さて、最後に私の質問です。誰かが私に教えてもらえますか?私のプロジェクトのどこにでもつながるアプローチはどれですか?ソースファイルの一部のみをantlrでスキャンする可能性はありますか?それとも、その目的のためにflexをantlrに接続する必要がありますか?constセクションまたはtypeセクションにないすべてのトークンを無視するようにantlrのパーサーに指示できますか?これらのツールは私のタスクには強力すぎますか?代わりに独自のルーチンを作成する必要がありますか?

4

2 に答える 2

2

Pascal 用のコンパイラを見つけて、必要な情報を報告するように変更するだけのほうがよいでしょう。おそらく、あなたの Pascal 用のそのようなコンパイラがあり、そのようなコンパイラのソース コードが利用できることがよくあります。

それ以外の場合は、基本的にパーサーを構築する必要があります。字句解析器を構築し、結果の語彙素をハッキングすることは、本質的に、その場しのぎの方法で不適切なパーサーを構築することです。ANTLR は良い方法です。特に Pascal の古い方言の場合、語彙素 (コメントをピックアップして無視する手段を含む) を非常に簡単に定義できます。必要な型情報には適切な BNF ルールが必要であり、それらのルールをパーサー ジェネレーターに変換します。作業を最小限に抑えるためにできることは、気にしない言語の部分のルールをごまかすことです。たとえば、割り当てステートメントの正確なサブグラマーを作成できます。それらを気にしないので、割り当てステートメントを識別子で始まり、その後に任意の他のトークンが続くものとして扱う、ずさんなサブグラマーを書くことができます。セミコロンで終わります。この種の文法は「島文法」と呼ばれます。正確である必要がある場合にのみ正確です。

再帰ビットについてはわかりません。各ファイルを個別に処理できない理由はありますか? 答えは、各型宣言についてどのような情報を知りたいかによって異なります。さらに深く掘り下げると、シンボル テーブルとアイランド パーサーが必要になる場合があります。パーサージェネレーターは、これに対して何の助けも提供しません。

于 2013-02-20T15:00:19.417 に答える
0

まず、他のブロック内にtypeブロックとconstブロックが存在する可能性があります(プロシージャ、後のDelphiバージョンではクラスもあります)。

さらに、実際にconstトークンをスキャンしてから、解析を開始できるかどうかは完全にはわかりません。Constは、最も一般的な(Borland)Pascal方言で他の目的にも使用されます。一部のキーワードは別のコンテキストで再利用できます。グローバルブロック構造を解析せず、特定の場所でconstとtypeのみを検索すると、誤ってそこで解析を開始します。

もちろん、基本的な問題はコメントです。スキャナーはできるだけ早くコメントを切り取り、それ以上は考慮しません。コメントがフィールドとして隣接するトークンに添付されるようにスキャナーを設定する必要があります(前にトークンに関連付けるか、特定のトークンが続くまでそれらを保存します)。

antlr対flexに関しては、手がかりはありません。私がPascalの解析でマイナーな経験を持っている唯一のパーサジェネレータは、Coco / R(Wirthiansに人気のあるパーサジェネレータ)ですが、一般的に私(および多くのパスカリアン)は手書きを好みます。

于 2013-02-20T11:48:41.560 に答える