コンパイラの作成コンパイラ-使用方法と機能に関する洞察


10

これは、言語設計で使用される概念をフレームワークの形で抽象化することを目的とした抽象化プロジェクトへの姉妹プロジェクトに焦点を当てた一連の質問の一部です。姉妹プロジェクトはOILexerと呼ばれ、一致時にコードインジェクションを使用せずに、文法ファイルからパーサーを構築することを目的としています。

構造タイピングに関連するこれらの質問に関連する他のいくつかのページは、ここに表示さ、使いやすさはここにあります。フレームワークに関する問い合わせに関連するメタトピックと投稿する適切な場所は、こちらにあります

特定の文法から解析ツリーの抽出を開始するところまで来ています。その後、DFAを使用して順方向パスを識別する再帰的降下パーサーが続きます(ANTLR 4のLL(*)と同様)。私はそれを開いて洞察を得るだろうと考えました。

パーサーコンパイラでは、どのような機能が理想的ですか?

これまでのところ、実装されているものの簡単な概要です:

  1. テンプレート
  2. 特定の時点で何が有効であるかを把握しながら、予測を先読みします。
  3. ルール内のリテラルを取得し、それらがどのトークンからのものであるかを解決するルール「非文字化」。
  4. 非決定的オートマトン
  5. 確定的オートマトン
  6. トークン認識のためのシンプルな字句状態マシン
  7. トークンの自動化方法:
    • スキャン-コメントに役立ちます:Comment:= "/ *" Scan( "* /");
    • 減算-識別子に便利です:識別子:= Subtract(IdentifierBody、Keywords);
      • 識別子がキーワードを受け入れないようにします。
    • エンコード-ベースN遷移のシリーズXカウントとしてオートメーションをエンコードします。
      • UnicodeEscape:= "\\ u" BaseEncode(IdentifierCharNoEscape、16、4);
        • 16進数の4遷移を使用して、Unicodeを16進数でエスケープします。これとの違い:[0-9A-Fa-f] {4}は、Encodeを使用した結果の自動化で、許可される16進値のセットをIdentifierCharNoEscapeのスコープに制限します。したがって、\ u005cを指定すると、エンコードバージョンは値を受け入れません。このようなことには重大な注意事項があります。控えめに使用してください。結果として生じる自動化は非常に複雑になる可能性があります。

実装されていないのはCST生成です。これを機能させるには、適切なコンテキストを引き継ぐように決定論的自動化を調整する必要があります。

興味のある方のために、T *y♯プロジェクトの元のフォームをかなり印刷したものをアップロードしました。各ファイルは他のすべてのファイルにリンクする必要があります。それらに従うために個別のルールでリンクを開始しましたが、時間がかかりすぎました(自動化の方が簡単だったでしょう)。

さらにコンテキストが必要な場合は、それに応じて投稿してください。

編集5-14-2013:特定の言語でステートマシンのGraphVizグラフを作成するコードを書きました。 これがAssemblyPartのGraphVizダイグラフです。言語の説明でリンクされているメンバーは、そのルールのダイグラフを含む相対フォルダーにrulename.txtを持っている必要があります。例を投稿してから一部の言語の説明が変更されました。これは、文法に関することを簡略化するためです。これが興味深いgraphviz画像です。


8
壁o 'テキスト。これを間違った方法で行わないでください。完全に説明された問題に感謝します。この場合、それは単に少し冗長すぎます。私が集めたものから、文法パーサーにどの機能を含める必要があるのか​​、またはゼロから始めずに機能を作成する方法を尋ねていますか?次の質問に回答するように編集してください(書き直す必要はなく、要約の最後に追加するだけです)。問題は何ですか?問題の考えられる解決策には、どのような制約がありますか(それは高速でなければならない、LL *でなければならない、など)?
Neil

1
機能セットについての洞察を求めています。焦点は使いやすさにあります。問題は、プロジェクトを知らない人を獲得することにあり、プロジェクトについての洞察を得て、プロジェクトに焦点を合わせていることを知らせます。私は「方法」を求めているのではなく、ユーザビリティに関連して尋ねています。質問をトリミングする方法についての提案は大歓迎です。
Allen Clark Copeland Jr 2013年

1
私にとって、プロジェクトの内容が明確ではありません。たとえば、yaccの時代以来、多くのパーサージェネレーターが見られます。OILexerの違いは何ですか?新しいものは何ですか?
2013年

1
このプロジェクトの目標は、パーサーの生成を簡素化することです。YACC / BisonおよびFLEX / LEXと同様です。主な違いは、これらのプログラムに伴う複雑さを回避することです。物事をシンプルかつ的確に保つことが主な目標です。これが、奇妙なセクショニングのないフォーマットを作成した理由ですが、むしろ目標は、それを通常のプログラミングに似せることです:言語開発にのみ固有です。トークンは名前の後に「:=」を使用して定義され、ルールは名前の後に「:: =」を使用して定義されます。テンプレートは、ルール構文を共有するため、引数に「<」と「>」を使用し、その後に「:: =」が続きます。
アレンクラークコープランドJr 2013年

3
解析に対するこの地獄の焦点は見当違いのようです。これは十分に解決された問題であり、プログラミング言語を処理するために必要なものにほとんど影響を与えません。「解析後の生活」に関する私のエッセイにGoogleを使用。
Ira Baxter

回答:


5

これは素晴らしい質問です。

私は最近多くの解析に取り組んできました、そして私見の主な機能のいくつかは:

  • プログラム的なAPI-理想的には、ライブラリをインポートするだけで、プログラミング言語内から使用できます。GUIまたはBNFのようなインターフェースも使用できますが、ツール、IDE、静的分析、テスト、言語抽象化機能、プログラマーの親しみやすさ、ドキュメントジェネレーター、ビルドプロセスを再利用できるため、プログラム的なインターフェースが重要です。加えて、小さなパーサーでインタラクティブに遊ぶことができるので、学習曲線が劇的に減少します。これらの理由により、「重要な機能」リストの一番上に配置されています。

  • @guyshermanが述べたように、エラー報告。エラーが見つかったとき、エラーがどこにあり、それが起こったときに何が起こっていたかを知りたいのです。残念ながら、バックトラックが発生したときに適切なエラーを生成する方法を説明するための適切なリソースを見つけることができませんでした。(ただし、以下の@ Sk-logicのコメントに注意してください)。

  • 部分的な結果。解析が失敗した場合、エラーの場所の前にあった入力の部分から何が正常に解析されたかを確認できるようにしたいと思います。

  • 抽象化。十分な機能を組み込むことはできず、ユーザーは常にもっと多くの機能を必要とするので、考えられるすべての機能を事前に理解しようとすると失敗します。これはテンプレートとはどういう意味ですか?

  • 私はあなたの#2(先読み予測)に同意します。良いエラーレポートを生成するのに役立つと思います。それは他の何かに役立ちますか?

  • 解析が発生したときに解析ツリーを構築するためのサポート。

    • 具体的な構文ツリー。ツリーの構造は文法に直接対応し、後のフェーズのエラー報告のためのレイアウト情報を含みます。この場合、クライアントは適切なツリー構造を取得するために何もする必要はありません。文法に直接依存する必要があります。
    • 抽象構文ツリー。この場合、ユーザーはすべての解析ツリーをいじることができます
  • ある種のロギング。これについてはよくわかりません。(たとえば)トークンを使用してHTMLドキュメントを生成する場合に、パーサーが試行したルールのトレースを表示したり、空白やコメントなどのジャンクトークンを追跡したりできます。

  • 文脈依存言語を処理する能力。これがどれほど重要かわからない-実際には、文脈自由文法を使用して言語のスーパーセットを解析し、その後の追加のパスで文脈依存制約をチェックする方がきれいに思えます。

  • カスタムエラーメッセージ。特定の状況でエラーレポートを調整し、問題をより迅速に理解して修正できるようにします。

一方、現在の進捗状況については最新ではありませんが、エラー修正は特に重要だとは思いません。私が気付いた問題は、ツールが提供する可能性のある修正が1)非常に多いこと、2)実際に行われた間違いに対応していないため、あまり役に立たないことです。うまくいけば、この状況が改善するでしょう(またはおそらくすでに改善しているでしょう)。


質問の本文を編集して、「テンプレート」という箇条書きにPrecedenceHelperへのリンクを含めました。パラメーター配列のタプルが許可されるため、4つのパラメーター(各パラメーター配列)がある場合、テンプレートは4つの引数セットで使用する必要があります。
アレンクラークコープランドジュニア2013年

CSTを作成する主な理由は、解析されたファイルの全体的なレイアウトです。ドキュメントをプリティプリントする場合は、CSTを使用するのが最善の策です。名前としてのASTは、CSTがキャプチャする奇数の間隔を処理するための情報が不足しているためです。CSTの変換は、優れたCSTであれば、通常は非常に簡単です。
アレンクラークコープランドジュニア2013年

使用可能な組み込み関数のトピックに関する質問を再度編集しました。
アレンクラークコープランドジュニア

私はテンプレート/関数について私のポイントを表現する素晴らしい仕事をしなかったと思います:私はあなたが十分に得ることができないので、システムが事前にそれらを理解しようとするべきではないことを意味しました:ユーザーが作成できる必要があります彼自身。

1
無限バックトラッキング(Packrat)を使用したエラー報告に特に役立つアプローチが1つ見つかりました。各プロダクションルールにはエラーメッセージ(「何とか何とか何とか予想される」という言葉)が付けられ、失敗するとそのようなメッセージが同じ方法でストリームに保存されますメモされたトークンとして。すべての障害を回復できない場合(ストリームの最後に到達する前に解析が終了した場合)、最も右のエラーメッセージ(またはそのようなメッセージのコレクション)が最も適切です。これが最も簡単なことです。もちろん、より多くのアノテーションを使ってさらに洗練させる方法があります。
SK-logic

5

言語設計の経験はありませんが、ゲームエンジン用のIDEを作成していたときに、一度パーサーを作成するのは初めてでした。

私の意見では、最終的なエンドユーザーにとって重要なのは、意味のあるエラーメッセージです。特に地球を壊滅させるポイントではないことは知っていますが、逆に言えば、これが重要な意味を持つことの1つは、誤検知を回避できる必要があるということです。誤検知はどこから発生しますか?それらは最初のエラーでパーサーが転倒し、完全に回復することはありません。C / C ++はこのことで悪名高くなっています(ただし、新しいコンパイラは少し賢いです)。

代わりに何が必要ですか?ある時点で何が有効/無効であるかを知るだけでなく、有効でないものを取り、それを有効にするための最小限の変更を行う方法を知っておく必要があると思います。これにより、関連する誤ったエラーを生成せずに解析を続行できます。混乱している再帰的な降下に。この情報を生成できるパーサーを構築できると、非常に堅牢なパーサーが得られるだけでなく、パーサーを使用するソフトウェアにいくつかの素晴らしい機能が提供されます。

これが事実である場合、私は本当に難しい、または愚かに明白な何かを申し訳ないかもしれないことに気づいています。これがあなたが探している種類のものではない場合、私は喜んで私の答えを削除します。


これは私が計画していることの1つです。ドメインに関する私の知識を手助けするために、私の友人は、自動化のコツをつかむために実際のパーサーを手動で書くことを提案しました。私がすぐに気付いたことの1つは、パーサーが複雑であり、プロセスを簡略化するために手動で行うことです。ルールとテンプレートは同じ構文を共有します。ただし、テンプレートでは有効であるがルールではない言語要素があり、このタスクを処理する内部状態があります。これにより、アイデアが思い浮かびました。サブルールの共有を容易にするために、ルールはパスエイドを指定できる必要があります。
アレンクラークコープランドジュニア2013年

...これはオートメーションに引き継ぐのはかなり簡単なはずですが、オートメーションには状態ベースの条件が必要です。私はこれに取り組み、あなたに連絡します。ANTLRは、有限状態の自動化を使用して、「T」*のサイクルを処理します。ここでは、ルールに800以上のバリエーションがある場合、削減が状態としてきれいになるため、ほとんどの解析プロセスを処理します(これは膨らむでしょう)標準のif / else形式のスパゲッティコードとして迅速に。)
Allen Clark Copeland Jr

0

文法には、「再帰ルールを残してはいけない」などの制限があってはなりません。今日広く使われているツールがこれを持っていることはばかげている、そしてyaccが正しく行ってからほぼ50年後のLL文法を吸うことしか理解できない。

正しい再帰の例(yacc構文を使用):

list: 
      elem                  { $$ = singleton($1); }
    | elem ',' list         { $$ = cons($1, $2);  }
    ;

左再帰の例(yacc synatxを使用):

funapp:
    term                    { $$ = $1; }
    | funapp term           { $$ = application($1, $2); }
    ;

さて、これは他のものに「リファクタリング」される可能性がありますが、どちらの場合でも、特定の種類の再帰はこれを書くための「正しい」方法です。 。

すべてを「リファクタリング」して、ツールが1つに課す左/右の再帰的フォームになるように要求するのではなく、自然な書き方をサポートする高度なツールから期待できます。


はい、そのような恣意的な制限がないのは良いことです。しかし、繰り返し演算子(正規表現*+数量詞など)に置き換えることができない左再帰の例は何ですか?私はこの分野の知識が限られていることを自由に認めますが、繰り返しにリファクタリングできない左再帰の使用に遭遇したことはありません。また、繰り返しバージョンもより明確になりました(ただし、これは個人的な好みです)。

1
@MattFenwick私の編集を参照してください。構文が直接構文ツリーを作成するための単純で自然なセマンティックアクション(たとえば)につながる方法に注意してください。(ところで、YACCでは使用できません)繰り返し、私はあなたが頻繁にあなたがなど空のリスト、シングルトン、得たかどうかを確認する必要があります推測している間
インゴ

ご回答ありがとうございます。私は理解が深まったと思います-これらの例をlist = sepBy1(',', elem)and として記述したいと思いますfunapp = term{+}(もちろんsepBy1+左/右再帰に関して実装され、標準の構文ツリーを生成します)。だから、左と右の再帰が悪いと思うのではなく、それらが低レベルであると感じて、物事をより明確にするために可能な限り高レベルの抽象化を使用したいというだけです。再度、感謝します!

1
@MattFenwickはどういたしまして。しかし、それはおそらく好みの問題です。私にとって、再帰は(少なくとも本質的に再帰的であるか、まったく興味がない言語のコンテキストでは)より自然な方法です。また、ツリーは再帰的なデータ構造であるため、再帰をシミュレートするために反復にフォールバックする必要はありません。しかし、もちろん、好みは異なります。
インゴ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.