独自のプログラミング言語とそのコンパイラを作成するにはどうすればよいですか[非公開]


427

私はプログラミングに精通しており、BASIC、FORTRAN、COBOL、LISP、LOGO、Java、C ++、C、MATLAB、Mathematica、Python、Ruby、Perl、JavaScript、アセンブリなどの言語に出会いました。人々がプログラミング言語を作成し、そのためのコンパイラを考案する方法を理解できません。また、Windows、Mac、UNIX、DOSなどのOSを人々がどのように作成するのかも理解できませんでした。私にとって不思議なもう1つのことは、人々がOpenGL、OpenCL、OpenCV、Cocoa、MFCなどのライブラリを作成する方法です。最後に理解できないのは、科学者がマイクロプロセッサ用のアセンブリ言語とアセンブラをどのように考案したかです。私はこれらすべてを本当に学びたいです。私は15歳です。私は常に、バベッジ、チューリング、シャノン、デニスリッチーなどのコンピューター科学者になりたいと思っていました。


私はすでにAhoのCompiler DesignとTanenbaumのOSコンセプトの本を読んでおり、それらはすべてコンセプトとコードを高レベルでしか議論していません。彼らは詳細やニュアンス、そしてコンパイラやオペレーティングシステムの考案方法には触れません。スレッド、セマフォ、プロセス、または解析とは何かを理解するだけでなく、自分で作成できるように具体的な理解が必要です。私は兄にこれについてすべて尋ねました。彼はMITのEECSのSBの学生であり、現実の世界でこれらすべてのものを実際に作成する方法の手がかりを持っていません。彼が知っているのは、皆さんが言及したようなコンパイラー設計とOSの概念(スレッド、同期、並行性、メモリー管理、字句解析、中間コード生成など)の理解だけです


あなたがUNIX / Linuxである場合は、専用のツールに関する情報を得ることができますlexyaccbison
mouviciel

私の最初の提案は、アホのドラゴンブックを読むことです。amazon.com/Compilers-Principles-Techniques-Alfred-Aho/dp/…–
ジュリアン

1
あまり役に立たないかもしれませんが、sites.google.com / site / steveyegge2 / blog -rants(Steve Yeggeのブログ)とsteve-yegge.blogspot.com/(Steve Yeggeの他のブログ)を読むことをお勧めします。
KK。

3
できるだけ多くのプログラミング言語を学びます。そうすれば、彼らの概念と間違いから学ぶことができます。巨人の肩の上に立つことができるのに、なぜ小人に満足するのですか?
-sbi

1
ヒント:インタープリターはコンパイラーよりも簡単です。これは、1行ずつ読み取る入力テキストに基づいて「何かをする」クラスです。別のヒント:これをリフレクションに結び付けると、スクリプトで任意のオブジェクトを制御できます。
デイブCousineau

回答:


407

基本的に、あなたの質問は「コンピュータチップ、命令セット、オペレーティングシステム、言語、ライブラリ、およびアプリケーションはどのように設計および実装されていますか?」です。これは数百万ドル規模の世界的な産業であり、その多くは専門家です。質問にもう少し焦点を合わせたいと思うかもしれません。

とはいえ、私は次の場所でクラックを取ることができます

人々がプログラミング言語を作成し、そのためのコンパイラを考案する方法を理解できません。

私には驚くべきことですが、多くの人がプログラミング言語を魔法のように見ています。パーティーなどで人々に会うとき、彼らが私に何をするか尋ねたら、プログラミング言語を設計し、コンパイラーとツールを実装することを伝えます。そして、人々-プロのプログラマー、あなたの心-が言う回数は驚くべきことです「うわー、私はそれについて考えたことはありませんが、ええ、誰かがそれらのものを設計する必要があります」。言語は、すでに完全にそれらの周りのツールインフラストラクチャで形成されていると考えていたようです。

それらは表示されません。言語は、他の製品と同じように設計されています。競合する可能性の中で慎重に一連のトレードオフを行います。コンパイラーとツールは、他のプロのソフトウェア製品と同じように構築されます。問題を分解し、一度に1行のコードを記述し、結果のプログラムから全体をテストします。

言語設計は大きなトピックです。言語の設計に興味がある場合、始めるのに適した場所は、あなたがすでに知っている言語の欠陥について考えることです。多くの場合、設計上の決定は、別の製品の設計上の欠陥を考慮することから生じます。

または、関心のあるドメインを検討し、そのドメインの問題の解決策を指定するドメイン固有言語(DSL)を設計します。ロゴに言及しました。これは、「線画」ドメイン用のDSLの優れた例です。正規表現は、「文字列でパターンを見つける」ドメインのDSLです。C#/ VBのLINQは、「データのフィルター、結合、並べ替え、およびプロジェクト」ドメイン用のDSLです。HTMLは、「ページ上のテキストのレイアウトを記述する」ドメインなどのDSLです。言語ベースのソリューションを受け入れられるドメインはたくさんあります。私のお気に入りの1つはInform7です。これは「テキストベースのアドベンチャーゲーム」ドメイン用のDSLです。おそらく私が今まで見た中で最高レベルの本格的なプログラミング言語でしょう。

言語をどのように見せたいかをスケッチしたら、合法および違法なプログラムを判断するためのルールを正確に書き留めてください。通常、これは次の3つのレベルで行います。

  1. 字句:言語内の単語の規則は何ですか、どの文字が合法か、数字はどのように見えるかなどです。
  2. 構文:言語の単語はどのように結合してより大きな単位になりますか?C#では、より大きな単位は式、ステートメント、メソッド、クラスなどのようなものです。
  3. セマンティック:構文的に合法なプログラムが与えられた場合、そのプログラム何をするのかをどのように把握しますか?

できる限り正確にこれらのルールを書き留めてください。それをうまくやれば、それをコンパイラまたはインタープリターを書くための基礎として使用できます。C#仕様またはECMAScript仕様を見て、私が何を言っているかを確認してください。それらは、合法プログラムを構成するものと、それが何をするかをどのように把握するかを記述する非常に正確な規則でぎっしり詰まっています。

コンパイラーの作成を開始するための最良の方法の1つは、高水準言語から高水準言語のコンパイラーを作成することです。ご使用の言語の文字列を取り込み、C#またはJavaScriptで文字列を出力するコンパイラーを作成します。その言語のコンパイラーに実行可能コードへの変換の面倒を見てもらいましょう。

C#、VB、VBScript、JavaScript、およびその他の言語とツールの設計に関するブログを書いています。このテーマに興味がある場合は、チェックしてください。http://blogs.msdn.com/ericlippert(historical)およびhttp://ericlippert.com(current)

特に、この投稿が面白いと思うかもしれません。ここでは、セマンティック分析中にC#コンパイラが実行するタスクのほとんどをリストします。ご覧のとおり、多くの手順があります。大きな分析の問題を、個別に解決できる一連の問題に分解します。

http://blogs.msdn.com/b/ericlippert/archive/2010/02/04/how-many-passes.aspx

最後に、高齢のときにこのようなことをする仕事を探している場合は、大学のインターンとしてマイクロソフトに来て、開発部門に入ることを検討してください。それが今日の仕事になった理由です!


CLRが自動的に最適化を実行できるため、コンパイラの最適化がどの程度行われていないかについて記述しましたか?

6
@Thorbjørn:用語について明確にしましょう。「コンパイラ」は、あるプログラミング言語から別のプログラミング言語に翻訳するデバイスです。C#をILに変換するC#コンパイラーと、ILをマシンコードに変換するILコンパイラー(「ジッター」)を持つ良い点の1つは、C#コンパイラーをILに(簡単に)書けることです。プロセッサ固有の最適化をジッタに入れます。コンパイラーの最適化が「行われていない」わけではなく、jitコンパイラー・チームが私たちのためにそれらを行っています。blogs.msdn.com/b/ericlippert/archive/2009/06/11/…を
Eric Lippert

6
@ Cyclotis04:Inform6はZコードにコンパイルされます。これは、バイトコードベースの仮想マシンの非常に初期の有名な例です。それが、1980年代のこれらすべてのInfocomゲームがメモリよりも大きく、複数のアーキテクチャに移植できるということです。ゲームはz-codeにコンパイルされ、コードメモリページングを備えたz-codeインタープリターが複数のマシンに実装されました。もちろん、必要であれば腕時計でzcodeインタープリターを実行できますが、当時はハイテクでした。詳細については、en.wikipedia.org / wiki / Z-machineを参照してください。
エリックリッパー

@EricLippertコンパイラはデバイスではありません。デバイスにはハードウェアが含まれます。入力データをマシンコードに変換するための一連のルールを持つ定義済みプログラム
dharam

2
@dhams:デバイスは、特定の目的のために作られたものです。私がこれまでに書いたすべてのコンパイラーは、コンパイラーの存在を可能にするために専用に設計されたハードウェアで実行されました。
エリックリッパー

127

Jack Crenshaw著 『コンパイラを構築しましょう』は、コンパイラとアセンブリ言語を書くための興味深い入門書です。

著者はそれを非常にシンプルに保ち、実際の機能を構築することに集中しました。


2
Crenshawのイントロの興味深い点は、あなたが気付くような問題にスマックをかけた時点で終了することです(ネタバレ:不完全です)。そして、完全な言語仕様を作成する必要がある場合、パーサーを生成するためのツールに入力できるように正式な表記法で記述してみませんか?そして、あなたは他のみんなと同じようにやっています。
親切な

3
@kindall、ツールを使用する理由があることを理解するために、手作業で行う必要があります。

72

「私はこのことを本当に学びたいです」。長期的に深刻な場合:

  • 大学に進み、ソフトウェアエンジニアリングを専門としています。あなたが得ることができるすべてのコンパイラクラスを取ります。クラスを提供する人々は、あなたよりも教育を受け、経験が豊富です。コードを読むことで決して得られない方法で情報を提示するために専門家の視点を使用するのは良いことです。

  • 高校を通じて数学の授業を続け、4年間すべて大学に進学します。非標準の数学に焦点を当てます:論理、群論、メタ数学。これにより、抽象的に考えるようになります。コンパイルに関する高度な理論論文を読んで、それらの理論が興味深く有用である理由を理解することができます。あなたが永遠に最新技術の背後にいたいなら、あなたはそれらの高度な理論を無視することができます。

  • 標準のコンパイラテキスト:Aho / Ullmanなどを収集/読み取ります。これらには、コミュニティが基本的に同意している内容が含まれています。それらの本のすべてを使用するわけではありませんが、その存在を知っておく必要があり、使用しない理由を知っておく必要があります。Muchnickは素晴らしいと思いましたが、かなり高度なトピック向けです。

  • コンパイラをビルドします。腐ったものを作って今すぐ始めましょう。これはいくつかの問題を教えてくれます。2つ目を作成します。繰り返す。この経験は、本の学習と大きな相乗効果を生み出します。

  • 始めるのに本当に良い場所は、BNF(Backus Naur Form)、パーサー、およびパーサージェネレーターについて学ぶことです。BNFは、コンパイラーランドで効果的に普遍的に使用されており、知らない場合は、仲間のコンパイラータイプと現実的に話すことはできません。

コンパイルの最初の優れた紹介と、ドキュメントだけでなくツール処理可能なメタ言語としてのBNFの直接的な価値が必要な場合は、「メタ」コンパイラ(コンパイラをビルドするコンパイラ)の構築に関するこのチュートリアル(私のものではない)を参照してください1964年の論文(はい、あなたはその権利を読んでいます)["META II構文指向コンパイラ記述言語" Val Schorre著。(http://doi.acm.org/10.1145/800257.808896)]このIMHOは、これまでに書かれた最高のcomp-sci論文の1つです。10ページでコンパイラコンパイラを構築することを教えます。最初にこの論文から学びました。

私が上で書いたのは個人的な経験から多くのことであり、それは私にかなり役立ったと思います。YMMV、しかし私見、あまりない。


54
-1上記のいずれも必要ありません。
ニールバターワース

77
@nbt上記のどれも必要ありません。しかし、上記のすべてが役立ちます。本当にたくさん。
コンラッドルドルフ

1
私は特に「数学を学んで抽象的に考える」ことに反対します。提案。「抽象的に考えることを学ぶ」ことは、独自のプログラミング言語とコンパイラを作成するのに特に役立つと思う場合でも(これらのラウンドアバウトを信じられないほど間接的なルートを取るよりも、実行することで学ぶ方がはるかに便利だと思います) 、抽象的思考を持つ分野は数学だけではありません!(私は数学者であるため、数学の使用を一般的に否定するのではなく、この特定のケースでの適用性だけを否定しています...)
grautur

26
コンパイラ理論に関する高度な技術論文を読みたい場合は、数学的な能力が必要です。あなたはその文献を無視することを決めることができ、あなたの理論、したがってコンパイラはそれに対して貧弱になるでしょう。ここでの否定者はすべて、多くの正式な教育なしでコンパイラーを構築できるという点を指摘し、同意します。彼らはあなたがそれなしで本当に良いコンパイラを構築できることを暗示しているようです。それは私が取りたいと思う賭けではありません。
アイラバクスター

7
CSは、言語の設計と実装に本当に役立つ学問です。もちろん必須ではありませんが、何十年にもわたって活用できる研究があり、他の間違いを繰り返す理由はまったくありません。
ドナルドフェローズ

46

これは、The Elements of Computing Systems:Building a Modern Computer from First Principlesと呼ばれるオンラインの書籍/コースです。

シミュレータを使用して、実際に完全なコンピュータシステムをゼロから構築します。多くのコメント者はあなたの質問が広すぎると述べていますが、この本は実際に非常に扱いやすいままで答えています。完了したら、独自のOSの機能を使用する高水準言語(設計した)でゲームを記述します。これは、コンパイラーによって(設計した)VM言語にコンパイルされ、 VMトランスレータによってアセンブリ言語(設計)に翻訳され、アセンブラによってマシンコード(設計)にアセンブルされます。アセンブラは、ブールロジックを使用して設計したチップから組み立てたコンピュータシステムで実行されます。シンプルなハードウェア記述言語。

章:

  1. コース概要
  2. ブール論理
  3. コンビナトリアルチップ
  4. シーケンシャルチップ
  5. 機械語
  6. コンピュータアーキテクチャ
  7. アセンブラ
  8. 仮想マシンI:算術演算
  9. 仮想マシンII:制御
  10. プログラミング言語
  11. コンパイラI:構文解析
  12. コンパイラーII:コード生成
  13. オペレーティング・システム
  14. リストアイテム

もっと楽しく


編集、不明な人に感謝します。私は数回試しましたが、説明に十分な焦点を当てることができませんでした...しかし、この本について言及したくありませんでした。この本は現在、Study Planリンクwww1.idc.ac.il/tecs/plan.htmlでオンラインになっています。また、オンラインで非常にリーズナブルな価格です。みんなお楽しみください。
ジョーインターネット

@ 12のステップでNANDからテトリスへ:私は10分のイントロをチェックアウトし、怠惰のために...この自分自身を提案するつもりだったyoutube.com/watch?v=JtXvUoPx4Qs
リチャード・アンソニー・ハイン

46

下がってください。コンパイラは、ある言語のドキュメントを別の言語のドキュメントに翻訳する単なるプログラムです。両方の言語は明確に定義され、特定される必要があります。

言語はプログラミング言語である必要はありません。ルールを書き留めることができる任意の言語を使用できます。おそらくGoogle Translateを見たことがあるでしょう。1つの言語(ドイツ語など)を別の言語(おそらく日本語)に翻訳できるため、これはコンパイラです。

コンパイラの別の例は、HTMLレンダリングエンジンです。入力はHTMLファイルで、出力は画面にピクセルを描画するための一連の指示です。

ほとんどの人がコンパイラについて話すとき、彼らは通常、高レベルのプログラミング言語(Java、C、Prologなど)を低レベルの言語(アセンブリまたはマシンコード)に翻訳するプログラムを指します。それは大変なことです。しかし、コンパイラは、ある言語を別の言語に翻訳するプログラムであるというジェネラリストの見方をすると、それほど悪くはありません。

文字列内のすべての単語を逆にするプログラムを作成できますか?例えば:

When the cat's away, the mice will play.

になる

nehW eht s'tac yawa, eht ecim lliw yalp.

書くのは難しいプログラムではありませんが、いくつかのことを考える必要があります。

  • 「言葉」とは何ですか?単語を構成する文字を定義できますか?
  • 言葉の始まりと終わりはどこですか?
  • 単語は1つのスペースだけで区切られていますか?
  • 句読点も逆にする必要がありますか?
  • 単語内の句読点はどうですか?
  • 大文字はどうなりますか?

これらの質問に対する回答は、言語を明確に定義するのに役立ちます。さあ、プログラムを書きましょう。おめでとうございます、あなたはコンパイラを書いたところです。

これについてはどうですか:一連の描画命令を受け取り、PNG(またはJPEG)ファイルを出力するプログラムを作成できますか?たぶんこのようなもの:

image 100 100
background black
color red
line 20 55 93 105
color green
box 0 0 99 99

繰り返しになりますが、言語を定義するにはいくつかのことを考える必要があります。

  • 原始的な命令とは何ですか?
  • 「ライン」という言葉の後には何がありますか?「色」の後に来るものは何ですか?同様に、「背景」、「ボックス」など。
  • 数字とは何ですか?
  • 空の入力ファイルは許可されていますか?
  • 単語を大文字にしても構いませんか?
  • 負の数は許可されますか?
  • 「image」ディレクティブを指定しないとどうなりますか?
  • 色を指定しなくても大丈夫ですか?

もちろん、答えるべき質問はまだありますが、それらを突き止めることができれば、言語を定義しています。翻訳を行うために作成するプログラムは、コンパイラーです。

コンパイラの作成はそれほど難しくありません。JavaまたはCで使用したコンパイラーは、これら2つの例のより大きなバージョンです。それでいいです!単純な言語を定義し、その言語に何かをさせるプログラムを作成します。遅かれ早かれ、言語を拡張したいと思うでしょう。たとえば、変数または算術式を追加できます。コンパイラーはより複雑になりますが、自分で作成したため、そのすべてを理解できます。それが、言語とコンパイラーの誕生です。


7
myFirstCompiler =(str)->( "" +(str || ""))。split( '')。reverse()。join( ''); jsfiddle.net/L7qSr
ラリーバトル

21

コンパイラの設計に興味がある場合は、Dragon Book(公式タイトル:Compilers:Principles、Techniques、and Tools)をご覧ください。このトピックに関する古典的な本と広く見なされています。


4
この本を最大限に活用するには、もう少し実際の経験が必要な場合があります。しかし、素晴らしい参考文献。

13
-1ドラゴンの本を読んだことがない人だけがドラゴンの本は良いと思うことができる。そしてそれは特に質問に対処していません。
ニールバターワース

33
ドラゴンブック?熱狂的な15歳の場合は?私は彼に彼の熱意をもう少し長く持たせたい。
デビッドソーンリー

1
よりアクセスしやすい代替手段:'Programming Language Pragmatics' 3e
-willjcroz

@DavidThornley彼を完全に数えないでください(はい、これは非常に古い投稿であることがわかります)。私は15歳で言語の仕組みを研究し始め、特に仮想マシンに焦点を当てました。現在、私は16歳であり、調査、執筆、および書き換えを数か月行った後、私は満足のいく実用的なインタープリターとコンパイラーを手に入れました。
デビッド


10

コンパイラやOSに何か魔法があるとは信じないでください。文字列内のすべての母音をカウントするために作成したプログラムを覚えていますか、または配列内の数字を加算しますか?コンパイラーの概念に違いはありません。それはずっとずっと大きいです。

すべてのプログラムには3つのフェーズがあります。

  1. いくつかのものを読む
  2. 処理する:入力データを出力データに変換する
  3. 他のデータを書き込む–出力データ

考えてみてください:コンパイラへの入力は何ですか?ソースファイルの文字列。

コンパイラからの出力は何ですか?ターゲットコンピューターへの機械命令を表すバイトの文字列。

それでは、コンパイラの「プロセス」フェーズとは何ですか?そのフェーズは何をしますか?

他のプログラムのように- -あなたはコンパイラがあると考える場合があるこれら三つの段階が含まれるように、あなたはコンパイラの構築方法の良いアイデアを持っています。


3
ニールが言ったように、本当だが有用ではない。再帰的な文法やシンボルテーブルのようなコンパイラの基本的な側面は、直感的に明らかではありません。
メイソンウィーラー

1
@Mason Wheeler:現実的にコンパイラの作成(およびターゲット言語の設計)を望んでいる人は誰でも、再帰的な文法シンボルテーブルはかなり基本的な概念だと思うでしょう。
FumbleFingers

8

私は専門家ではありませんが、ここに私の刺し傷があります:

あなたはコンパイラを書くことについて尋ねるのではなく、ただアセンブラを書くように思われます。これは本当に魔法ではありません。

SO(https://stackoverflow.com/questions/3826692/how-do-i-translate-assembly-to-binary)から他の誰かの答えを盗むと、アセンブリは次のようになります:

label:  LDA #$00
        JMP label

次に、アセンブラを介して実行し、次のようになります。

$A9 $00
$4C $10 $00

次のように、すべて潰れています。

$A9 $00 $4C $10 $00

それは本当に魔法ではありません。

メモ帳はASCII(16進数ではない)を使用するため、メモ帳で作成することはできません。16進エディタを使用するか、単にプログラムでバイトを書き出します。その16進数をファイルに書き込み、「a.exe」または「a.out」という名前を付けて、OSに実行するように指示します。

もちろん、最新のCPUとオペレーティングシステムは非常に複雑ですが、それが基本的な考え方です。

新しいコンパイラを作成する場合は、次のようにします。

1)pyparsing(または他の適切な解析フレームワーク)の計算機の例のようなものを使用して、インタープリター言語を記述します。これにより、解析の基本を理解することができます。

2)翻訳者を作成します。言語を、たとえばJavascriptに翻訳します。これで、言語がブラウザで実行されます。

3)LLVM、C、Assemblyなどの下位レベルの翻訳者を作成します。

ここで停止できます。これはコンパイラです。それは最適化コンパイラではありませんが、それは問題ではありませんでした。また、リンカーとアセンブラーの作成を検討する必要があるかもしれませんが、本当にしたいですか?

4)(非常識)オプティマイザーを作成します。大規模なチームは、これについて何十年も働きます。

4)(正気)既存のコミュニティに参加します。GCC、LLVM、PyPy、あらゆるインタープリターに取り組んでいるコアチーム。


8

いくつかの他の人が優れた答えを与えています。さらにいくつかの提案を追加します。まず、あなたがやろうとしていることの良い本は、AppelのModern Compiler Implementationテキストです(CJava、またはStandard MLを選んでください)。この本では、最小限のランタイムサポートライブラリとともに、エミュレーターで実行できるMIPSアセンブリーへの単純な言語用のコンパイラーの完全な実装を紹介します。コンパイルされた言語を機能させるために必要なすべてを1回パスする場合、それは非常に良い本です1

Appelは、事前に設計された言語をコンパイルする方法を説明しますが、さまざまな言語機能の意味や、独自の設計の相対的なメリットの観点から考える方法にあまり時間をかけません。その面では、プログラミング言語:概念と構成はまともです。コンピュータープログラミングの概念、手法、およびモデルは、単一言語(Oz)のコンテキストでそれを行っていますが、言語設計について深く考えるのに適した本でもあります。

最後に、AppelのテキストはC、Java、およびStandard MLにあると述べました。コンパイラの構築とプログラミング言語について真剣に考えているなら、MLを学び、Appelのそのバージョンを使用することをお勧めします。MLファミリの言語には強力な型システムがあり、主に機能的です。機能は他の多くの言語とは異なるため、機能的言語をまだ知らない場合に学習すると、言語スキルが向上します。また、パターンマッチングと機能的な考え方は、コンパイラで頻繁に行う必要がある種類の操作に非常に適しているため、MLベースの言語で記述されたコンパイラは、通常、Cで記述されたコンパイラよりもはるかに短く、理解しやすく、 Java、または同様の言語。 ハーパーの本Standard MLでは、始めるのに非常に良いガイドです。これを実行することで、Appelの標準MLコンパイラー実装ブックを使用する準備が整います。Standard MLを学習すれば、後の作業のためにOCamlを簡単に選択できます。IMO、働くプログラマーのためのより良いツールがあります(周囲のOS環境とよりきれいに統合し、実行可能プログラムを簡単に生成し、そしてulexやMenhirのような素晴らしいコンパイラ構築ツールを持っています)。


1長期的な参照としては、パーサーアルゴリズムの内部動作など、参照する可能性のあるものについての詳細があり、さまざまなアプローチの広範なカバレッジがあるので、ドラゴンブックが好きですが、アペルの本は非常に良いです最初のパス。基本的に、Appelは、コンパイラー全体を通して物事を行う1つの方法を教え、それをガイドします。ドラゴンブックでは、さまざまなデザインの代替案を詳細に説明していますが、何かを機能させる方法に関するガイダンスははるかに少ないです。


編集:誤ったAho参照をSethiに置き換え、CTMCPに言及。


ええと、大学通訳クラスのプログラミング言語の必需品がありました。ひどかった。私も個人的にスキームが好きで、構文を気にしません、それは私のためにそれを台無しにした概念の著者の不十分な説明でした。
グレッグGuida

私はAppelが継続してコンパイルするのが好きですが、彼の本には多くの事前知識があると思いました。
ジョンハロップ

6

大学のクラス用のコンパイラを作成する必要がありました。

これを行う基本的なことは、あなたが思うほど複雑ではありません。最初のステップは、文法を作成することです。英語の文法を考えてください。同様に、主語と述語が含まれる文を解析できます。詳細については、Context Free Grammarsをご覧ください。

文法(言語の規則)が決まったら、コンパイラーを書くのは、それらの規則に従うのと同じくらい簡単です。通常、コンパイラはマシンコードに変換されますが、x86を学習したい場合を除き、MIPSを検討するか、独自の仮想マシンを作成することをお勧めします。

コンパイラには通常、スキャナーとパーサーの2つの部分があります。基本的に、スキャナーはコードを読み取り、トークンに分離します。パーサーは、これらのトークンの構造を調べます。その後、コンパイラはいくつかのかなり単純なルールを実行して、必要なコード(アセンブリ、バイトコードなどの中間コードなど)に変換します。あなたがそれをますます小さな破片に分解するならば、これは最終的に全く気が遠くなりません。

幸運を!


8
概念的に簡単ですか?はい。本当にシンプル?いいえ
ニールバターワース

7
うん コンパイラは、スキャン/解析後、型チェック/推論、最適化、レジスタ割り当てなどを行う必要があります。これらの手順は単純ではありません。(インタープリターコードを使用する場合は、これらの部分をランタイムステージまで延期します。)
Macke

私からの賛成票はありません:コンパイラには2つの基本的な部分がありますが、1つはプログラムの抽象的な記述(通常はスキャンと解析に分割されます)を構築し、もう1つはその抽象的な記述のバージョンをもう一度書くことですその他の形式(たとえば、マシンコード)。(サイドノート:最適化コンパイラーは、通常、抽象的な記述を書き出す前に改善しようとしますが、それは改良です。)
ドナルフェローズ

6

Petzoldの著書Codeは、第一原理から始めて、技術者でも技術者でもない人への素晴らしい入門書です。非常に読みやすく、その範囲は広すぎず、行き詰まりません。

これを書いたので、もう一度読み直さなければなりません。



5

このスレッドには優れた答えがありますが、私も同じ質問をしていたので、私のものを追加したかっただけです。(また、Joe-Internetが提案した本は優れたリソースであることを指摘したいと思います。)

まず、コンピューターがどのように機能するかという質問です。これは、入力->計算->出力です。

最初に「計算」部分を検討します。入力と出力がどのように機能するかについては、後で説明します。

コンピュータは、本質的にプロセッサ(またはCPU)とメモリ(またはRAM)で構成されます。メモリは、それぞれが有限数のビットを格納できる場所の集合であり、そのような各メモリ場所はそれ自体が番号で参照できます。これは、メモリ場所のアドレスと呼ばれます。プロセッサは、データをフェッチできるガジェットですメモリから、データに基づいていくつかの操作を実行し、メモリにデータを書き戻します。プロセッサは、メモリからデータを読み取った後、何を読み、何をするかをどのように判断しますか

これに答えるには、プロセッサの構造を理解する必要があります。以下はかなり単純なビューです。プロセッサは基本的に2つの部分で構成されています。1つは、プロセッサ内に構築され、作業メモリとして機能するメモリロケーションのセットです。これらは「レジスタ」と呼ばれます。2つ目は、レジスタ内のデータを使用して特定の操作を実行するために構築された電子機器の束です。「プログラムカウンタ」または「pc」と「命令レジスタ」またはirと呼ばれる2つの特別なレジスタがあります。プロセッサは、メモリが3つの部分に分割されていると見なします。最初の部分は「プログラムメモリ」で、実行中のコンピュータープログラムを保存します。2つ目は「データメモリ」です。3番目はいくつかの特別な目的に使用されます。これについては後で説明します。プログラムカウンターには、プログラムメモリから読み取る次の命令の場所が含まれています。命令カウンターには、実行中の現在の操作を示す数値が含まれています。プロセッサが実行できる各操作は、操作のオペコードと呼ばれる番号で参照されます。コンピュータの基本的な動作は、プログラムカウンタが参照するメモリ位置を命令レジスタに読み込むことです(そして、次の命令のメモリ位置を指すようにプログラムカウンタをインクリメントします)。次に、命令レジスタを読み取り、目的の操作を実行します。たとえば、命令は特定のメモリ位置をレジスタに読み込むか、あるレジスタに書き込むか、2つのレジスタの値を使用して何らかの操作を実行し、出力を3番目のレジスタに書き込むことができます。命令カウンターには、実行中の現在の操作を示す数値が含まれています。プロセッサが実行できる各操作は、操作のオペコードと呼ばれる番号で参照されます。コンピュータの基本的な仕組みは、プログラムカウンタが参照するメモリ位置を命令レジスタに読み込むことです(そしてプログラムカウンタをインクリメントして、次の命令のメモリ位置を指すようにします)。次に、命令レジスタを読み取り、目的の操作を実行します。たとえば、命令は特定のメモリ位置をレジスタに読み込むか、何らかのレジスタに書き込むか、2つのレジスタの値を使用して何らかの操作を実行し、3番目のレジスタに出力を書き込むことができます。命令カウンターには、実行中の現在の操作を示す数値が含まれています。プロセッサが実行できる各操作は、操作のオペコードと呼ばれる番号で参照されます。コンピュータの基本的な仕組みは、プログラムカウンタが参照するメモリ位置を命令レジスタに読み込むことです(そしてプログラムカウンタをインクリメントして、次の命令のメモリ位置を指すようにします)。次に、命令レジスタを読み取り、目的の操作を実行します。たとえば、命令は特定のメモリ位置をレジスタに読み込むか、何らかのレジスタに書き込むか、2つのレジスタの値を使用して何らかの操作を実行し、3番目のレジスタに出力を書き込むことができます。プロセッサが実行できる各操作は、操作のオペコードと呼ばれる番号で参照されます。コンピュータの基本的な仕組みは、プログラムカウンタが参照するメモリ位置を命令レジスタに読み込むことです(そしてプログラムカウンタをインクリメントして、次の命令のメモリ位置を指すようにします)。次に、命令レジスタを読み取り、目的の操作を実行します。たとえば、命令は特定のメモリ位置をレジスタに読み込むか、何らかのレジスタに書き込むか、2つのレジスタの値を使用して何らかの操作を実行し、3番目のレジスタに出力を書き込むことができます。プロセッサが実行できる各操作は、操作のオペコードと呼ばれる番号で参照されます。コンピュータの基本的な仕組みは、プログラムカウンタが参照するメモリ位置を命令レジスタに読み込むことです(そしてプログラムカウンタをインクリメントして、次の命令のメモリ位置を指すようにします)。次に、命令レジスタを読み取り、目的の操作を実行します。たとえば、命令は特定のメモリ位置をレジスタに読み込むか、何らかのレジスタに書き込むか、2つのレジスタの値を使用して何らかの操作を実行し、3番目のレジスタに出力を書き込むことができます。コンピュータの基本的な仕組みは、プログラムカウンタが参照するメモリ位置を命令レジスタに読み込むことです(そしてプログラムカウンタをインクリメントして、次の命令のメモリ位置を指すようにします)。次に、命令レジスタを読み取り、目的の操作を実行します。たとえば、命令は特定のメモリ位置をレジスタに読み込むか、何らかのレジスタに書き込むか、2つのレジスタの値を使用して何らかの操作を実行し、3番目のレジスタに出力を書き込むことができます。コンピュータの基本的な仕組みは、プログラムカウンタが参照するメモリ位置を命令レジスタに読み込むことです(そしてプログラムカウンタをインクリメントして、次の命令のメモリ位置を指すようにします)。次に、命令レジスタを読み取り、目的の操作を実行します。たとえば、命令は特定のメモリ位置をレジスタに読み込むか、何らかのレジスタに書き込むか、2つのレジスタの値を使用して何らかの操作を実行し、3番目のレジスタに出力を書き込むことができます。

さて、コンピューターはどのように入出力を実行しますか?非常に簡単な答えを提供します。http://en.wikipedia.org/wiki/Input/outputおよびhttp://en.wikipedia.org/wiki/Interruptを参照してください。多くのための。メモリの3番目の部分と割り込みと呼ばれるものの2つを使用します。コンピューターに接続されているすべてのデバイスは、プロセッサーとデータを交換できる必要があります。これは、前述のメモリの3番目の部分を使用して行われます。プロセッサは各デバイスにメモリのスライスを割り当て、デバイスとプロセッサはそのメモリのスライスを介して通信します。しかし、プロセッサは、どの場所がどのデバイスを指しているのか、いつデバイスがデータを交換する必要があるのか​​をどのようにして知るのでしょうか?ここで割り込みが発生します。割り込みは、本質的には、現在の状態を一時停止し、すべてのレジスタを既知の場所に保存してから別の処理を開始するためのプロセッサへの信号です。多数の割り込みがあり、それぞれが一意の番号で識別されます。割り込みごとに、それに関連付けられた特別なプログラムがあります。割り込みが発生すると、プロセッサは、割り込みに対応するプログラムを実行します。BIOSとハードウェアデバイスがコンピューターのマザーボードにどのように接続されているかに応じて、すべてのデバイスが一意の割り込みとメモリのスライスを取得します。BIOSの助けを借りてオペレーティングシステムを起動すると、各デバイスの割り込みとメモリの場所が決定され、デバイスを適切に処理するための割り込み用の特別なプログラムが設定されます。そのため、デバイスがデータを必要とする場合、またはデータを送信する必要がある場合、割り込みを通知します。プロセッサは、実行中の処理を一時停止し、割り込みを処理してから、実行中の処理に戻ります。hdd、キーボードなど、さまざまな種類の割り込みがあります。重要なのは、定期的な間隔で割り込みを呼び出すシステムタイマーです。ソフトウェア割り込みと呼ばれる割り込みをトリガーできるオペコードもあります。

これで、オペレーティングシステムがどのように機能するかをほぼ理解できました。OSが起動すると、OSはタイマー割り込みを設定し、OSに一定の間隔で制御を与えます。また、他のデバイスなどを処理するために他の割り込みを設定します。コンピューターが多数のプログラムを実行し、タイマー割り込みが発生すると、OSが制御を取得し、プロセス管理、メモリ管理などの重要なタスクを実行します。また、OSは通常、プログラムがデバイスに直接アクセスするのではなく、ハードウェアデバイスにアクセスする抽象的な方法。プログラムがデバイスにアクセスする場合、OSが提供するいくつかのコードを呼び出してから、デバイスと通信します。これらには、並行性、スレッド、ロック、メモリ管理などを扱う多くの理論があります。

現在、理論的にはオペコードを使用してプログラムを直接書くことができます。これは、マシンコードと呼ばれるものです。これは明らかに非常に苦痛です。プロセッサのアセンブリ言語は、これらのオペコードのニーモニックに過ぎず、プログラムの作成が容易になります。単純なアセンブラは、アセンブリで記述されたプログラムを取得し、ニーモニックを適切なオペコードに置き換えるプログラムです。

プロセッサとアセンブリ言語の設計についてはどうですか。コンピュータアーキテクチャに関する本をいくつか読む必要があることを知るため。(joe-internetで参照される本の1章から7章を参照)。これには、ブール代数、加算や乗算などの単純な組み合わせ回路の構築方法、メモリや順序回路の構築方法、マイクロプロセッサの構築方法などの学習が含まれます。

では、コンピューター言語をどのように書くのでしょうか。マシンコードで簡単なアセンブラーを書くことから始めることができます。次に、そのアセンブラを使用して、Cの単純なサブセットのコンパイラを記述します。次に、そのCのサブセットを使用して、より完全なバージョンのCを記述します。もちろん、言語を書くには、最初に言語を設計する必要があります(プロセッサを設計するのと同じ方法です)。もう一度その上でいくつかの教科書を見てください。

そして、どのようにOSを書くのでしょうか。まず、x86などのプラットフォームをターゲットにします。次に、どのように起動し、OSがいつ呼び出されるかを把握します。典型的なPCはこの方法で起動します。起動し、BIOSがいくつかのテストを実行します。次に、BIOSはhddの最初のセクターを読み取り、コンテンツをメモリ内の特定の場所にロードします。次に、CPUをセットアップして、このロードされたデータの実行を開始します。これは、osが呼び出されるポイントです。この時点での典型的なOSは、残りのメモリをロードします。次に、デバイスを初期化し、他の設定を行い、最後にログイン画面を表示します。

したがって、OSを作成するには、「ブートローダー」を作成する必要があります。次に、割り込みとデバイスを処理するコードを記述する必要があります。次に、プロセス管理、デバイス管理などのすべてのコードを記述する必要があります。次に、OSで実行されているプログラムがデバイスやその他のリソースにアクセスできるようにするAPIを記述する必要があります。そして最後に、ディスクからプログラムを読み取り、プロセスとして設定して実行を開始するコードを記述する必要があります。

もちろん、私の答えは明らかに単純化されており、おそらくほとんど実用的ではありません。私の弁護では、私は理論上の大学院生であるため、これらのことの多くを忘れてしまいました。しかし、あなたはこれらの多くのグーグルをグーグルで調べて、さらに調べることができます。


4

私はあなたと同じような混乱状態にあったときの私のプログラミングキャリアのポイントを思い出すことができます。それをすべてまとめる方法の手がかり。

何一緒にそれを結ぶなかったことにする具体的なプロジェクト見つけることだったんを(私はすべての理論の小さいサブセットに必要なことを見つける当時と)。

Java VMは良い出発点を提供してくれました。概念的には「プロセッサー」ですが、実際のCPUの乱雑な詳細から非常に抽象化されています。また、学習プロセスの重要で見過ごされがちな部分も提供します。物を分解してから再び組み立てる(昔は子供たちがラジオセットを使っていたように)。

Javaの逆コンパイラとHello、Worldクラスで遊んでください。JVMの仕様を読んで、何が起こっているのかを理解してください。これは単にコンパイラがされているもので、あなたに接地洞察力を与えること

次に、Hello、Worldクラスを作成するコードで遊んでください。(実際には、Hello、Worldとしか言えない高度に専門化された言語のために、アプリケーション固有のコンパイラを作成しています。)

Hello、他の言語で書かれたWorldで読み取り、同じクラスを出力できるコードを書いてみてください。文字列を「Hello、World」から別のものに変更できるようにします。

次に、「2 *(3 + 4)」などの算術式を計算するクラスを(Javaで)コンパイルしてみます。このクラスを分解して、再び組み立てることができる「おもちゃのコンパイラ」を作成します。


3

1)ワシントン大学からの素晴らしいビデオ講義:

CSE P 501コンパイラの構築-2009年秋www.cs.washington.edu/education/courses/csep501/09au/lectures/video.html *

2)SICP http://groups.csail.mit.edu/mac/classes/6.001/abelson-sussman-lectures/ 同じ名前の本。これは実際、ソフトウェアエンジニアにとって必須です。

3)また、関数型プログラミング、Haskell、ラムダ計算、セマンティクス(表示を含む)、および関数型言語のコンパイラー実装について。Haskellを既に知っている場合は、2005-SS-FP.V10.2005-05-24.HDVから開始できます。 Uxxビデオが答えです。最初にVxxビデオをフォローしてください。

http://video.s-inf.de/#FP.2005-SS-Giesl.(COt).HD_Videoaufzeichnung

(ビデオは英語ですが、他のコースはドイツ語です。)

  • 新規ユーザーは、最大2つのハイパーリンクのみを投稿できます。

3

ANTLRは良い出発点です。LexやYaccに似た言語生成フレームワークです。プロセスを簡素化するANTLRWorksというGUIがあります。

.NETの世界には、.NETの世界でコードを生成するために使用できる動的言語ランタイムがあります。DLRを使用してコードを生成するZentrumという式言語を作成しました。静的および動的に型指定された式を解析および実行する方法を示します。


2

コンパイラがどのように動作し、独自のプログラミング言語を作成するかを簡単に紹介するには、OS / CPUの内部、つまりレクサー、パーサーを知らなくても言語設計理論に焦点を当てた新しい本http://createyourproglang.comをお勧めします。、通訳など

最近人気のあるCoffee ScriptおよびFancyプログラミング言語の作成に使用されたものと同じツールを使用します。


2

あなたが言うことがすべて真実であるなら、あなたは有望な研究者のプロフィールを持っています、そして、具体的な理解は1つの方法だけで得られます:勉強すること。そして、私は「この天才によって書かれたこれらすべての高レベルのコンピューターサイエンスの本(特にこれらを読んでください!」と言っているのではありません。つまり、Charles Babbage、Alan Turing、Claude Shannon、Dennis Ritchieなどのコンピューター科学者になるためには、ハイレベルな人々と一緒にいなければなりません。私は独学の人(私もその一人です)を軽(していませんが、あなたのような人はあまりいません。私は真剣にお勧めシンボリックシステムプログラム(SSP)スタンフォード大学を。彼らのウェブサイトが言うように:

スタンフォード大学のシンボリックシステムプログラム(SSP)は、コンピューターと心に焦点を当てています。情報を表すためにシンボルを使用する人工および自然のシステムです。SSPは、人間とコンピューターの関係のさまざまな側面に関心のある学生と教員を結び付けます。

  • 認知科学:人間の知能、自然言語、脳を計算プロセスとして研究します。
  • 人工知能:コンピューターに人間のような行動と理解を与える; そして
  • 人間とコンピューターの相互作用:ユーザーとうまく機能するコンピューターソフトウェアとインターフェイスを設計します。

2

Pythonを学ぶ(またはRubyかもしれませんが、Pythonでより多くの経験を持っているので、これから説明します)少し残された分野を少し提案します。そして、単に手を出しただけでなく、実際に深いレベルでそれを知るようになります。

これをお勧めする理由はいくつかあります。

  1. Pythonは非常によく設計された言語です。いくつかのイボがありますが、他の多くの言語よりもIMHOが少ないです。あなたが新進の言語デザイナーであるなら、できるだけ多くの良い言語に身をさらすのは良いことです。

  2. Pythonの標準実装(CPython)はオープンソースであり、十分に文書化されているため、内部で言語がどのように機能するかを簡単に理解できます。

  3. Pythonは、アセンブリよりも理解しやすく、Pythonが動作するすべてのプラットフォームで同じように機能する単純なバイトコードにコンパイルされます。したがって、コンパイル(Pythonはソースコードをバイトコードにコンパイルするため)と解釈(このバイトコードはPython仮想マシンで解釈されるため)について学習します。

  4. Pythonには多くの提案された新機能があり、番号付きのPEP(Python Enhancement Proposals)に文書化されています。言語設計者が実際に機能を実装する方法を選択する前に、機能の実装をどのように検討したかを確認するために読んで興味深いPEP。(まだ考慮中のPEPは、この点で特に興味深いです。)

  5. Pythonにはさまざまなプログラミングパラダイムの機能が混在しているため、問題を解決するためのさまざまな方法について学習し、独自の言語に含めることを検討する幅広いツールを用意します。

  6. Pythonでは、デコレータ、メタクラス、インポートフックなどを使用してさまざまな方法で言語を簡単に拡張できるため、実際に言語を離れることなく、ある程度まで新しい言語機能を試すことができます。(余談ですが、コードのブロックはRubyのファーストクラスのオブジェクトですので、ループなどの新しい制御構造を実際に書くことができます! Rubyでプログラムします。しかし、それはかなりクールです。)

  7. Pythonでは、コンパイラによって生成されたバイトコードを実際に逆アセンブルしたり、独自のコードをゼロから作成してインタープリターに実行させたりすることができます(私はこれを自分でやったのですが、面白くて楽しかったです)。

  8. Pythonには解析用の優れたライブラリがあります。Pythonコードを抽象構文ツリーに解析し、ASTモジュールを使用して操作できます。PyParsingモジュールは、設計した言語などの任意の言語の解析に役立ちます。理論的には、必要に応じてPythonで最初の言語コンパイラを作成できます(C、アセンブリ、またはPython出力さえ生成できます)。

この調査アプローチは、使用している言語で学習した概念を認識し始めるため、より形式的なアプローチとうまくいく可能性があります。

楽しんで!


pythonを掘ることではありませんが、それは重要です。子供は既に大きなNに対してN個の言語を持っています。Nを増やしてもそれほど違いはありません。Cを例にとります。それは標準です。たくさんのライブラリがあります。クロスプラットフォームです(標準に準拠する場合)。出力を逆アセンブルできます。CFrontを書くことができます。など。
イアン

1

さて、あなたの質問は、「コンピュータサイエンスの学位の実用的な中核概念は何か」と書き直すことができると思います。

基本的に、独自のプログラミング言語コンパイラを作成するには、テキストファイルを読み取り、そこから情報を抽出し、読み取った情報に基づいて、読み取り可能なバイトに変換するまでテキストに変換を実行します。ローダー(レバインのリンカーとローダーを参照)。些細なコンパイラは、初めて行われたとき、かなり厳密なプロジェクトです。

オペレーティングシステムの中心はカーネルであり、リソース(メモリの割り当て/割り当て解除など)を管理し、タスク/プロセス/プログラムを切り替えます。

アセンブラは、テキスト->バイト変換です。

このようなことに興味があるなら、標準のX86アセンブリの一部のサブセットをサポートするX86アセンブラをLinuxで作成することをお勧めします。これは非常に簡単なエントリポイントであり、これらの問題を紹介します。これは小さなプロジェクトではなく、多くのことを教えてくれます。

Cで書くことをお勧めします。Cは、そのレベルの作業の共通語です。


1
一方、これは非常に高レベルの言語に適した場所です。ファイル内の個々のバイトを指定できる限り、どの言語でもコンパイラー/アセンブラー(より簡単)を作成できます。言う、perl。またはVBA。天国、可能性!
イアン

1

Kenneth Loudenの本「Compiler Construction」を参照してください。

http://www.cs.sjsu.edu/~louden/cmptext/

コンパイラー開発へのより実践的なアプローチを提供します。

人々はやって学ぶ。ボード上でシンボルが走り書きされ、すぐに理論から実践にジャンプできるのはごく少数です。残念ながら、それらの人々はしばしば独断的で、原理主義者であり、それについて最も騒々しいです。


1

私は最初のアセンブリ言語としてPDP-8に触れることができて幸運でした。PDP-8には6つの命令しかありませんでした。これは非常に単純なため、実際にはいくつかの個別のコンポーネントによって実装されると想像するのは簡単でした。それは実際にコンピューターから「魔法」を取り除きました。

同じ啓示への別のゲートウェイは、Knuthが例で使用している「ミックス」アセンブリ言語です。「ミックス」は今日では古風なように見えますが、それでもそのDEの謎を解く効果があります。


0

コンパイラーとプログラミング言語(および1つを構築することを含むすべて-有限文法の定義やアセンブリーへの変換など)は非常に複雑なタスクであり、システム全体について十分な理解が必要です。このタイプのコースは通常、大学の3年生から4年生のComp Sciクラスとして提供されます。

まず、オペレーティングシステム全般と、既存の言語がどのようにコンパイル/実行されるか(つまり、ネイティブ(C / C ++)、VM(Java)、またはインタープリター(Python / Javascript)で)をよく理解することを強くお勧めします。

私はオペレーティングシステムコース(2年目)で、Abraham Silberschatz、Peter B. Galvin、Greg Gagneの著書 『Operating System Concepts』を使用したと思います。これは優れた本であり、オペレーティングシステムの各コンポーネントを徹底的に説明しました。少し高価ですが価値があり、古い/使用済みのコピーが浮かんでいるはずです。


OSの概念?コンパイラを構築するために必要なことはほとんどありません。必要なのは、ソフトウェアアーキテクチャを理解することです。アドレス空間、スタック、スレッド(コンパイラーを学びたい場合は、並列処理とその将来についてよりよく学びます)。
イラバクスター

言語設計とコンパイラを学びたいと言った直後、彼はOSについて学びたいと言った。
デビッドソーンリー

@Ira-同意しました。OSを理解することがコンパイラ/言語を構築するために必要であることを決して述べず、簡単な出発点であるかもしれないと簡単に説明しました。誰もが彼の質問の「コンパイラ」の側面に焦点を当てていますが、彼はまた、OSとライブラリのより良い理解を望んでいると述べました。15歳はまだアーキテクチャについての学習のために、それはメモリ管理を理解することがはるかに有用であろう、スレッド、ロック、I / O、など。YACC(私見)と文法を定義する方法を学ぶより
天蓋

申し訳ありません...(構築?)OSについて学びたいという点を逃しました。私の要点は、コンパイラーに多くのOS知識は必要ないということです。実際、コンパイラーとOSが相互作用して集合的な目的を達成する場合を除いて、まったく異なるトピックです。(Multicsでは、グローバルVMを有効にするために、特定の方法で関数呼び出しを構築するためにPL / 1コンパイラが必要でした)。
アイラバクスター

0

それは大きなトピックですが、代わりに「本を読んで、子供に」という気前の良いことであなたを追い払うのではなく、頭を包むのを助けるためのポインタを喜んで与えます。

ほとんどのコンパイラーやインタープリターは次のように機能します。

トークン化:コードテキストをスキャンし、トークンのリストにそれを破ります。

文字列をスペースで分割することはできないため、この手順は難しい場合がありますif (bar) foo += "a string";。8つのトークンのリストであるWORD、OPEN_PAREN、WORD、CLOSE_PAREN、WORD、ASIGNMENT_ADD、STRING_LITERAL、TERMINATOR を認識する必要があります。ご覧のとおり、スペースでソースコードを分割するだけでは機能しません。各文字をシーケンスとして読み取る必要があります。したがって、英数字に遭遇した場合は、英数字以外の文字とその文字列をヒットするまで文字を読み続けます読んだばかりの単語は、後でさらに分類される単語です。"a string"トークナイザーの粒度は、STRING_LITERALと呼ばれる1つのトークンとして飲み込んで後で解析するか、または"a string" OPEN_QUOTE、UNPARSED_TEXT、CLOSE_QUOTE、その他何でも、これはコーディング中に自分で決めなければならない多くの選択肢の1つにすぎません。

Lex:これでトークンのリストができました。最初のパスでは、各文字列のコンテキストを理解しようとしてあまり労力を費やさないため、おそらくWORDのようなあいまいな分類でいくつかのトークンにタグを付けました。したがって、ソーストークンのyoutリストを再度読み取り、言語のキーワードに基づいて、より具体的なトークンタイプで各曖昧なトークンを再分類します。「if」などのWORDがあり、「if」がシンボルIFという特別なキーワードのリストにあるため、そのトークンのシンボルタイプをWORDからIF、および特別なキーワードリストにないWORDに変更します。 、WORD fooなどはIDENTIFIERです。

解析:したがってif (bar) foo += "a string";、次のような字句トークンのリストを作成しました:IF OPEN_PAREN IDENTIFER CLOSE_PAREN IDENTIFIER ASIGN_ADD STRING_LITERAL TERMINATOR。ステップは、トークンのシーケンスをステートメントとして認識することです。これは解析中です。これは、次のような文法を使用して行います。

STATEMENT:= ASIGN_EXPRESSION | IF_STATEMENT

IF_STATEMENT:= IF、PAREN_EXPRESSION、STATEMENT

ASIGN_EXPRESSION:= IDENTIFIER、ASIGN_OP、VALUE

PAREN_EXPRESSSION:= OPEN_PAREN、VALUE、CLOSE_PAREN

値:= IDENTIFIER | STRING_LITERAL | PAREN_EXPRESSION

ASIGN_OP:= EQUAL | ASIGN_ADD | ASIGN_SUBTRACT | ASIGN_MULT

「|」を使用するプロダクション 用語間は「これらのいずれかに一致する」ことを意味し、用語間にコンマがある場合は「この一連の用語に一致する」ことを意味します

これはどのように使用しますか?最初のトークンから始めて、トークンのシーケンスをこれらの制作物と一致させてください。最初にトークンリストをSTATEMENTと照合しようとすると、STATEMENTのルールを読んで「STATEMENTはASIGN_EXPRESSIONまたはIF_STATEMENTのいずれか」と表示されるため、ASIGN_EXPRESSIONと最初に一致しようとするため、ASIGN_EXPRESSIONの文法ルールを検索します「ASIGN_EXPRESSIONはIDENTIFIERで、その後にASIGN_OPが続き、VALUEが続くため、IDENTIFIERの文法規則を検索すると、IDENTIFIERの文法規則はないので、IDENTIFIERはそれ以上必要ないという意味の「端末」を意味します。トークンを直接照合するために解析しますが、最初のソーストークンはIFであり、IFはIDENTIFIERと同じではないため、一致は失敗しました。今何?STATEMENTルールに戻り、次の用語IF_STATEMENTに一致させようとします。IF_STATEMENTをルックアップし、IFで始まり、IFをルックアップし、IFがターミナルであり、最初のトークンとターミナルを比較し、IFトークンが一致し、次の用語がPAREN_EXPRESSIONであり、PAREN_EXPRESSIONをルックアップします。これはターミナルではなく、最初の用語ですPAREN_EXPRESSIONはOPEN_PARENで始まり、OPEN_PARENを検索します。これは端末であり、OPEN_PARENを次のトークンに一致させます。

このステップにアプローチする最も簡単な方法は、parse()という関数を使用して、一致させようとしているソースコードトークンと、一致させようとしている文法用語を渡すことです。文法用語が端末でない場合、再帰的です。同じソーストークンとこの文法規則の最初の用語を渡してparse()を再度呼び出します。これが「再帰降下パーサー」と呼ばれる理由ですそこからparse()。

parse()がASIGN_EXPRESSIONなどのプロダクションに一致するたびに、そのコードを表す構造体を作成します。この構造には、元のソーストークンへの参照が含まれます。これらの構造のリストを作成し始めます。この構造全体を抽象構文ツリー(AST)と呼びます

コンパイルおよび/または実行:文法の特定のプロダクションに対して、AST構造が与えられた場合、そのASTのチャンクをコンパイルまたは実行するハンドラー関数を作成しました。

それでは、タイプASIGN_ADDを持つASTの一部を見てみましょう。インタープリターとして、ASIGN_ADD_execute()関数があります。この関数はの解析ツリーに対応するASTの一部として渡されるためfoo += "a string"、この関数はその構造を調べ、構造の最初の用語はIDENTIFIERでなければならず、2番目の用語はVALUEであることがわかっているため、ASIGN_ADD_execute() VALUE用語をVALUE_eval()関数に渡します。この関数は、メモリ内の評価値を表すオブジェクトを返します。その後、ASIGN_ADD_execute()は変数テーブルで「foo」のルックアップを行い、eval_value()によって返されたものへの参照を格納します関数。

それは通訳です。コンパイラーは、代わりにハンドラー関数を使用して、ASTを実行する代わりにバイトコードまたはマシンコードに変換します。

手順1〜3、および一部4は、FlexやBisonなどのツールを使用して簡単に作成できます。(aka。Lex and Yacc)しかし、通訳を自分でゼロから書くことは、おそらくプログラマーが達成できる最も強力な運動です。他のすべてのプログラミングの課題は、この課題をサミットした後は些細なことのようです。

私のアドバイスは小さなものから始まります。小さな言語で、小さな文法で、いくつかの簡単な文を解析して実行してから、そこから成長していきます。

これらを読んで、幸運を祈ります!

http://www.iro.umontreal.ca/~felipe/IFT2030-Automne2002/Complements/tinyc.c

http://en.wikipedia.org/wiki/Recursive_descent_parser


2
人々がコンパイルについて考えるとき、あなたは私が古典的な間違いだと思うことをします:それは問題が構文解析についてであると信じていることです。パーシングは技術的に簡単です。それを行うための優れた技術があります。コンパイルの難しい部分は、セマンティック分析、プログラム表現の高低レベルでの最適化、コードの生成であり、最近ではPARALLELコードがますます重要になっています。あなたはあなたの答えでこれを完全に平凡にします:「コンパイラはASTをバイトコードに変換するハンドラ関数を持っているでしょう」。そこにはコンパイラ理論とエンジニアリングの隠れた50年が隠されています。
アイラバクスター

0

コンピュータ分野は、多くの方向に進化する時間があったため、複雑になっています。本質的には、計算するマシンについてです。

私のお気に入りの非常に基本的なコンピューターは、Harry PorterのRelay Computerです。これは、コンピューターが基本レベルでどのように動作するかの風味を与えます。次に、言語やオペレーティングシステムなどが必要な理由を理解し始めることができます。

問題は、何が必要なのを理解せずに何も理解するのが難しいことです。幸運を祈ります。物を読むだけではありません。 やるものを。



-1

もう1つの優れた入門書は、1986年のN. Wirthの「Compilerbau」(コンパイラー構成)で、約100ページの長さで、パーサー、コードジェネレーター、仮想マシンを含む玩具言語PL / 0の簡潔で適切に設計されたコードについて説明しています。また、文法を読み込んでEBNF表記で解析するパーサーの作成方法も示します。この本はドイツ語ですが、演習として要約を書いてコードをPythonに翻訳しました。http: //www.d12k.org/cmplr/w86/intro.htmlを参照してください


-1

プログラミング言語の本質を理解することに興味がある場合は、PLAI(http://www.cs.brown.edu/~sk/Publications/Books/ProgLangs/)の本を読んで概念を理解し、それらの実装。また、独自の言語の設計にも役立ちます。


-1

コンパイラに本当に興味があり、かつて一度も興味がなかった場合は、算術式を計算するための計算機(エリックが述べたようなDSLのようなもの)を設計することから始めることができます。この種のコンパイラについて考慮する必要がある多くの側面があります。

  • 許可された番号
  • 許可されたオペレーター
  • オペレーターの優先順位
  • 構文検証
  • 可変ルックアップメカニズム
  • サイクル検出
  • 最適化

たとえば、次の式がある場合、計算機はxの値を計算できるはずです。

a = 1
b = 2
c = a + b
d = (3 + b) * c
x = a - d / b

開始するのは極端に難しいコンパイラーではありませんが、コンパイラーとは何かという基本的な考え方をもっと考えさせ、プログラミングスキルを向上させ、コードの品質を制御するのに役立ちます(これは実際には完璧な問題ですテスト駆動開発TDDは、ソフトウェア品質の改善に適用できます)。

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