タグ付けされた質問 「compilers」

ある言語(ソース言語)のコードを読み取り、それを別の言語(ターゲット言語)の同等のプログラムに変換するプログラムに関する質問。

4
残された再帰がなぜ悪いのですか?
この質問は、コンピューターサイエンススタック交換で回答できるため、理論的コンピューターサイエンススタック交換から移行されました。 6年前に移行され ました。 コンパイラの設計で、なぜ文法で再帰を残すべきなのですか?私はそれが無限再帰を引き起こす可能性があるからだと読んでいますが、正しい再帰文法にも当てはまりませんか?

3
任意の文脈自由文法の解析、ほとんどが短い断片
ユーザー定義のドメイン固有の言語を解析したい。これらの言語は通常、数学表記に近いものです(自然言語を解析していません)。ユーザーは次のようにBNF表記でDSLを定義します。 expr ::= LiteralInteger | ( expr ) | expr + expr | expr * expr 入力のようなもの1 + ( 2 * 3 )は受け入れられなければならず、入力のようなもの1 +は不正確であるとして拒否され、入力のようなもの1 + 2 * 3は曖昧なものとして拒否されなければなりません。 ここでの中心的な困難は、あいまいな文法をユーザーフレンドリーな方法で対処することです。文法を曖昧でないように制限することは選択肢ではありません。それが言語のやり方です。つまり、曖昧さを避けるために必要でない場合は、括弧を省略するほうが好ましいという考え方です。式が曖昧でない限り、解析する必要があり、そうでない場合は拒否する必要があります。 私のパーサーは、文脈に依存しない文法、あいまいなものでも動作し、すべての明確な入力を受け入れなければなりません。受け入れられたすべての入力に解析ツリーが必要です。無効またはあいまいな入力の場合、理想的には適切なエラーメッセージが必要ですが、最初に取得できるものを取り上げます。 私は通常、比較的短い入力でパーサーを呼び出しますが、入力は時々長くなります。したがって、漸近的に高速なアルゴリズムは最良の選択ではないかもしれません。入力が20シンボル未満の約80%、20〜50シンボルの19%、まれに1%のより長い入力の分布に最適化したいと思います。無効な入力の速度は大きな問題ではありません。さらに、DSLが1000〜100000入力ごとに変更されることを期待しています。数分ではなく、文法の前処理に数秒費やすことができます。 典型的な入力サイズを考慮して、どの解析アルゴリズムを調査する必要がありますか?エラー報告は私の選択の要因である必要がありますか、それとも明確な入力の解析に集中し、エラーフィードバックを提供するために完全に別個の低速なパーサーを実行する必要がありますか? (それが必要なプロジェクト(しばらく前)では、CYKを使用しました。これは実装するのにそれほど難しくなく、入力サイズに適切に機能しましたが、非常に良いエラーを生成しませんでした。)


2
多くの業界で使用されているコンパイラで、継続渡しスタイルよりも静的単一割り当てが優先されるのはなぜですか?
静的単一割り当て(SSA)に関するウィキペディアのページによると、SSAはLLVM、GCC、MSV、Mono、Dalvik、SpiderMonkey、V8などの大規模で有名なプロジェクトで使用されていますが、継続渡しスタイルを使用するプロジェクトのページ(CPS)は比較して少し欠けています。 私は、CPSが主に機能言語を実装するコンパイラーとインタープリターによって好まれるというこの考えを持っています-特に、HaskellとSchemeは、突然変異の制限またはファーストクラスの継続サポートの必要性のために、CPSスタイルに強い傾向があるようです(私は推測します) Smalltalkでもこれが必要になる可能性があります)。私がCPSを使用している主要な文献は、主にSchemeに取り組んでいるか、何らかの点でSchemeに関連している文献のようです。 採用の勢いのほかに、SSAが業界で使用される特別な理由はありますか?SSAとCPSは密接な関係があります。つまり、別の観点から述べることは簡単ですが、情報表現はCPSにとってはコンパクトであるか、効率が低い可能性があります。

1
なぜ字句解析と構文解析を分離するのですか?
ステートマシンからの単一のパスを使用してドキュメントを解析することが可能です。2つのパスを持つことの利点は何ですか?テキストをトークンに変換するレクサーと、それらのトークンの生産ルールをテストするパーサーがありますか?生産ルールをテキストに直接適用する単一のパスを用意していないのはなぜですか?

1
製品タイプとタイプ推論
私は、連結言語用のコンパイラに取り組んでおり、型推論のサポートを追加したいと考えています。Hindley–Milnerは理解していますが、型理論を学んでいるので、それをどのように適応させるかわかりません。次のシステムは健全で、決定的に推測できますか? 用語は、リテラル、用語の構成、用語の引用、またはプリミティブです。 e::=x∣∣ee∣∣[e]∣∣…e::=x|ee|[e]|… e ::= x \:\big|\: e\:e \:\big|\: [e] \:\big|\: \dots すべての用語は関数を示します。2つの関数およびe 2の場合、e 1e1e1e_1e2e2e_2並置が逆組成を示しています。リテラルはニラディック関数を示します。e1e2=e2∘e1e1e2=e2∘e1e_1\:e_2 = e_2 \circ e_1 構成以外の用語には、基本的なタイプルールがあります。 x:ι[Lit]Γ⊢e:σΓ⊢[e]:∀α.α→σ×α[Quot],α not free in Γx:ι[Lit]Γ⊢e:σΓ⊢[e]:∀α.α→σ×α[Quot],α not free in Γ \dfrac{}{x : \iota}\text{[Lit]} \\ \dfrac{\Gamma\vdash e : \sigma}{\Gamma\vdash [e] : \forall\alpha.\:\alpha\to\sigma\times\alpha}\text{[Quot]}, \alpha \text{ not free in } \Gamma 連結言語にはアプリケーションルールがないため、アプリケーションのルールは特にありません。 型は、リテラル、型変数、またはスタックからスタックへの関数のいずれかです。ここで、スタックは右ネストされたタプルとして定義されます。すべての関数は、「残りのスタック」に関して暗黙的にポリモーフィックです。 τρσ::=ι∣∣α∣∣ρ→ρ::=()∣∣τ×ρ::=τ∣∣∀α.στ::=ι|α|ρ→ρρ::=()|τ×ρσ::=τ|∀α.σ …

2
consのどのプロパティにより、末尾再帰モジュロconsを排除できますか?
私は、基本的な末尾再帰除去の考え方に精通しています。そこでは、呼び出し自体の直接の結果を返す関数を反復ループとして書き直すことができます。 foo(...): # ... return foo(...) また、特別な場合として、再帰呼び出しがの呼び出しでラップされている場合、関数を書き換えることができることも理解していconsます。 foo(...): # ... return (..., foo(...)) これをcons許可するプロパティは何ですか?cons再帰的な末尾呼び出しを繰り返し書き換える能力を損なうことなく折り返すことができる以外の機能は何ですか? GCC(Clangではない)は、この「末尾再帰モジュロ乗算」の例を最適化できますが、どのメカニズムがこれを発見できるのか、またはどのように変換するのかは不明です。 pow(x, n): if n == 0: return 1 else if n == 1: return x else: return x * pow(x, n-1)



3
バイナリデータにレクサー/パーサーを使用するのはなぜ間違っているのですか?
私はしばしばパーサーコンビネーターとは対照的にレクサー / パーサーで作業し、解析でクラスを取ったことがない人を見て、バイナリデータの解析について尋ねます。通常、データはバイナリであるだけでなく、コンテキスト依存でもあります。これは基本的に、1種類のトークン(バイト用トークン)のみを持つことになります。 レクサー/パーサーによるバイナリデータの解析が、解析クラスを受講していないが、理論に基づいたCS学生にとって十分に明確である理由を誰かが説明できますか?

2
演算子の左関連付けを維持しながら、文法の左再帰を削除する
この演習に問題があります: λ計算の次のあいまいな文法をGとします。 E → v | λv.E | EE | (E) ここで、Eは単一の非終端記号、λv.EはEの変数vに関する抽象化を表し、EEはアプリケーションを表します。 L(G ')= L(G)となるようなLL(1)文法G'を定義し、次の通常の規則を課すことでGのあいまいさを解決します。 抽象化は正しい連想です。 アプリケーションは関連付けられたままです。 アプリケーションは、抽象化よりも優先されます。 G 'のLL(1)解析テーブルと、文字列の解析時に取得された解析ツリーを表示しますλv1. λv2. v1v2v1。 あいまいさの設定の優先順位と関連付けを排除し、次の文法を取得しました。 E -> EF | F F -> λv.G | G G -> (E) | v これはLL(1)ではありません。これは、生成E -> EFが再帰的に行われるためです。しかし、私が得るその生産から左再帰を排除します: E -> FE¹ E¹-> FE¹ | ɛ F -> …

3
「森林破壊」はプログラムから「木」をどのように削除しますか?
私はどのように森林伐採が消費理解だと思うと同時に、リストを生成し(倍からと展開]機能- ここにコードレビューでこの良い答えを参照)、しかし、私はそれを比較した場合、技術上のWikipediaのエントリ、それは削除する「について話しましたプログラムからの木。 プログラムを構文解析ツリーに解析する方法は理解できます(そうですか?)が、プログラムのある種の単純化(それ?)に森林破壊を使用する意味は何ですか?そして、どのように自分のコードにそれをしますか?

2
LL(k)とLR(k)の文法を区別する方法はありますか?
私は最近、コンパイラの設計について勉強しています。LL文法とLR文法の2種類の文法について知りました。 また、すべてのLL文法がLRであり、LL文法がLR文法の適切なサブセットであるという事実も知っています。1つ目はトップダウン解析で使用され、2つ目はボトムアップ解析で使用されます。 しかし、特定の文法がLLまたはLRであると言えるようにする方法はありますか?

3
この文法LL(1)はどうですか?
これはドラゴンブックからの質問です。これは文法です: S→AaAb∣BbBaS→AaAb∣BbBaS \to AaAb \mid BbBa A→εA→εA \to \varepsilon B→εB→εB \to \varepsilon 質問では、それがLL(1)であってSLR(1)ではないことをどのように示すかを尋ねます。 それがLL(1)であることを証明するために、構文解析テーブルを作成してみましたが、セル内で複数のプロダクションを取得していますが、これは矛盾しています。 このLL(1)の状態と、それを証明する方法を教えてください。

1
「CPS」アプローチは、SML / NJのパフォーマンスに大きな悪影響を与えました。推論が望ましい
Learning F# へのコメント:関数の概念を学ぶために、他のプログラミング言語を使用してF#に翻訳できる書籍はどれですか。マカリウスは述べた: 「CPS」アプローチは、SML / NJのパフォーマンスに大きな悪影響を与えていることに注意してください。その物理的評価モデルは、ハードウェアに組み込まれているあまりにも多くの仮定に違反しています。Isabelle / HOLのようなSMLの大きなシンボリックアプリケーションを使用する場合、CPSを使用したSML / NJは約5倍になります。従来のスタックのPoly / MLよりも100倍遅い。 誰かがこの理由を説明できますか?(できればいくつかの例で)インピーダンスの不一致はありますか?

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