web-dev-qa-db-ja.com

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

私はプログラミングに精通しており、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のコンパイラデザインとTanenbaumのOSコンセプトブックを読みましたが、それらはすべて、コンセプトとコードを高レベルでのみ説明しています。詳細やニュアンス、コンパイラやオペレーティングシステムの考案方法については触れません。スレッド、セマフォ、プロセス、または解析とは何かを理解するだけでなく、自分で作成できるように具体的な理解が必要です。私はこれについて兄に尋ねました。彼はEECSのSBの学生で、MIT=であり、実際にこれらすべてのものを実際に作成する方法の手がかりはありません。コンパイラーの設計とOSを理解しているだけです。皆さんが述べたような概念(つまり、スレッド、同期、並行性、メモリ管理、字句解析、中間コード生成など)

427
Dave

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

そうは言っても、私は次の場所で亀裂をとることができます。

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

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

彼らはただ現れるだけではありません。言語は、他の製品と同じように設計されています。競合する可能性の間で一連のトレードオフを慎重に行うことによってです。コンパイラーとツールは、他のプロフェッショナルソフトウェア製品と同様に構築されます。問題を分解し、一度に1行のコードを記述して、結果のプログラムをテストします。

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

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

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

  1. lexical:言語の単語の規則は何ですか、どの文字が有効か、数字はどのように見えるかなどです。
  2. syntactic:言語の単語はどのようにしてより大きな単位に結合されますか? C#では、より大きな単位は、式、ステートメント、メソッド、クラスなどです。
  3. semantic:構文的に合法なプログラムが与えられた場合、プログラムがが何をするかをどのように理解しますか

これらのルールをできるだけ正確に書き留めてください。あなたがそれをうまくやれば、それをコンパイラやインタプリタを書くための基礎として使うことができます。 C#仕様またはECMAScript仕様を調べて、私の意味を確認してください。それらは、合法的なプログラムを構成するものと、それが何をするかを理解する方法を説明する非常に正確なルールでぎっしりと詰まっています。

コンパイラーの作成を始める最良の方法の1つは、高水準言語から高水準言語コンパイラーを作成することです。自分の言語の文字列を受け取り、C#やJavaScriptなどの偶然知っている言語で文字列を吐き出すコンパイラーを作成します。次に、その言語のコンパイラーに、実行可能なコードに変換するという面倒な作業を任せます。

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

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

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

最後に、あなたが年を取っているときにこのようなことをする仕事を探しているなら、大学のインターンとしてマイクロソフトに来て、開発部門に入ろうとすることを検討してください。それで今日の仕事になりました!

407
Eric Lippert

Lets Build a Compiler によって、Jack Crenshawがコンパイラとアセンブリ言語を書くための興味深い入門書を見つけるかもしれません。

著者はそれを非常にシンプルに保ち、実際の機能の構築に焦点を合わせました。

127
user1249

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

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

  • 高校で数学の授業に専念し、4年間すべて大学に進みます。非標準の数学に焦点を当てます:論理、群論、メタ数学。これはあなたに抽象的な思考を強いるでしょう。それはあなたがコンパイルに関する高度な理論の論文を読んで、それらの理論がなぜ興味深く有用であるのかを理解することを可能にします。あなたが永遠に最先端の技術の背後にいたい場合は、それらの高度な理論を無視できます。

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

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

  • 始めるのに本当に良い場所は、BNF(バッカスナウアフォーム)、パーサー、およびパーサージェネレーターについて学ぶことです。 BNFは、コンパイラーランドで効果的に広く使用されており、知らなければ、他のコンパイラータイプと現実的に対話することはできません。

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

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

72
Ira Baxter

従うことができるオンラインの本/コースと呼ばれる コンピューティングシステムの要素:第一原理から現代のコンピューターを構築する です。

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

章:

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

もっと楽しく

46
Joe Internet

下がってください。コンパイラは、ある言語のドキュメントを別の言語のドキュメントに変換するプログラムです。どちらの言語も明確に定義され、具体的である必要があります。

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

コンパイラのもう1つの例は、HTMLレンダリングエンジンです。その入力はHTMLファイルで、出力はピクセルを画面に描画するための一連の命令です。

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

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

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つの例のより大きなバージョンにすぎません。ぜひお試しください!単純な言語を定義し、その言語で何かを実行するプログラムを記述します。後で言語を拡張する必要があります。たとえば、変数や算術式を追加したい場合があります。コンパイラはより複雑になりますが、自分で記述したので、そのすべてを理解できます。それが言語とコンパイラがどうやってできるかです。

46
Barry Brown

コンパイラの設計に興味がある場合は、 ドラゴンブック (公式タイトル:コンパイラ:原理、技法、およびツール)を確認してください。これは、このトピックに関する古典的な本と広く見なされています。

21
Brian Agnew

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

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

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

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

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

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

他のプログラムと同様に、コンパイラがhasをこれらの3つのフェーズに含めることを検討した場合、コンパイラがどのように構築されるかについてのアイデア。

10
Pete Wilson

「コンパイラを作ろう」はすでに提案されていました。 Turbo Pascalの代わりにHaskellを使用する「モダン」バージョンがあります: http://alephnullplex.appspot.com/blog/view/2010/01/12/lbach-1-introduction

Haskellを使用して、さらにアイデアを提供できる非常に有益なSchemeインタプリタがあります: 48時間でスキーマを記述

10
Landei

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

コンパイラを書くことを求めているのではなく、単にアセンブラを求めているだけです。これは本当に魔法ではありません。

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
wisty

他のいくつかは優れた答えを出しました。さらにいくつかの提案を追加します。まず、あなたがやろうとしていることのための良い本は、AppelのModern Compiler Implementationテキストです( [〜#〜] c [〜#〜]Java 、または Standard ML )。この本では、最小限のランタイムサポートライブラリと共に、エミュレーターで実行できるMIPSアセンブリーへの単純な言語Tigerのコンパイラーの完全な実装について説明します。コンパイルされた言語を機能させるために必要なすべてを1回で通過する場合、それはかなり良い本です1

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

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


1パーサーアルゴリズムの内部の仕組みや、さまざまなアプローチを幅広くカバーしているなど、私が参照する可能性が高いことについてより詳細に説明しているので、長期的な参照にはドラゴンブックを好みますが、Appelのブックは最初のパス。基本的に、Appelはコンパイラー全体を通して物事を行う1つの方法を教え、それをガイドします。ドラゴンブックでは、さまざまなデザインの代替案を詳細に説明していますが、何かを機能させる方法についてのガイダンスははるかに少なくなっています。


編集済み:不適切なAho参照をSethiで置き換え、CTMCPについて言及します。

8

大学の授業用にコンパイラーを作らなければなりませんでした。

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

文法(言語の規則)が下がると、コンパイラーの作成はそれらの規則に従うだけで簡単になります。コンパイラは通常、マシンコードに変換されますが、x86を学びたくない場合は、MIPSを参照するか、独自の仮想マシンを作成することをお勧めします。

コンパイラ は通常、スキャナとパーサの2つの部分で構成されます。基本的に、スキャナーはコードを読み込み、トークンに分離します。パーサーはこれらのトークンの構造を調べます。次に、コンパイラーはいくつかのかなり単純な規則に従って、必要なコード(アセンブリ、バイトコードなどの中間コードなど)に変換します。どんどん小さくしていくと、結局これはまったく気が遠くなるようなものではありません。

幸運を!

6
Jerr

Petzoldの本 Code は、第一原理から始めて、非技術者と技術者の両方を紹介する優れた入門書です。それは非常に読みやすく、その範囲は広大で、あまり行き詰まることはありません。

これを書いたので、もう一度読む必要があります。

6
Kevin Won

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

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

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

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

これに答えるには、プロセッサの構造を理解する必要があります。以下はかなり単純なビューです。プロセッサは基本的に2つの部分で構成されます。 1つは、ワーキングメモリとして機能する、プロセッサ内に構築された一連のメモリ位置です。これらは「レジスタ」と呼ばれます。 2つ目は、レジスターのデータを使用して特定の操作を実行するために構築された電子機械の集まりです。「プログラムカウンター」またはpcと呼ばれる2つの特別なレジスターと「命令レジスター」またはirがあります。プロセッサは、メモリが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から提供されたコードを呼び出し、デバイスと通信します。これらには、並行性、スレッド、ロック、メモリ管理などを扱う理論がたくさんあります。

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

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

今、どのようにコンピュータ言語を書くのですか?マシンコードで簡単なアセンブラを書くことから始めることができます。次に、そのアセンブラを使用して、Cの単純なサブセットのコンパイラを記述します。次に、そのCのサブセットを使用して、より完全なバージョンのCを記述します。最後に、Cを使用して、pythonなどのより複雑な言語を記述します。 =またはC++。もちろん、言語を書くには、最初にそれを設計する必要があります(プロセッサの設計と同じ方法)。

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

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

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

5
dubyaman

StackOverflowでこの優れた質問(および回答)を確認することをお勧めします: Learning To Compiler 。リソースの幅広いリストが含まれています。

5
Angry Lettuce

私のプログラミングのキャリアの中で、あなたと同じような混乱状態にあったときのことを思い出すことができます。私は理論をかなり読みましたが、ドラゴンの本、タイガーの本(赤)ですが、まだそれほど多くはありませんでした。すべてをまとめる手がかり。

それを結びつけたのはdoへの具体的なプロジェクトを見つけることでした(そして、私はすべての理論の小さなサブセットしか必要としないことを発見しました)。

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

デコンパイラーとJavaのHello、Worldクラスをいじってください。 JVM仕様を読んで、何が起こっているのかを理解してください。これにより、コンパイラが何であるかについての根拠のある洞察doingが得られます。

次に、作成 Hello、Worldクラスのコードをいじってみます。 (実際には、Hello、Worldとしか言えない非常に専門的な言語のために、アプリケーション固有のコンパイラーを作成しています。)

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

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

4
Morendil

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
Zura

[〜#〜] antlr [〜#〜] は良い出発点です。これは、LexやYaccに似た言語生成フレームワークです。プロセスを簡略化する ANTLRWorks と呼ばれるGUIがあります。

.NETの世界では、 Dynamic Language Runtime を使用して、.NETの世界でコードを生成できます。 DLRを使用してコードを生成する Zentrum という式言語を作成しました。静的および動的に型付けされた式を解析および実行する方法を示します。

3
Sean

あなたが言うすべてが本当であるならば、あなたは有望な研究者のプロフィールを持っています、そして具体的な理解は一つの方法でのみ得ることができます:勉強。そして、私は「 これらすべての高レベルのコンピュータサイエンスの本を読んでください (特に これら )これによって書かれた 天才 !」とは言っていません。つまり、チャールズバベッジ、アランチューリング、クロードシャノン、デニスリッチーなどのコンピューター科学者になるには、高レベルの人々と一緒にいなければなりません。私は独学の人を軽蔑しているわけではありませんが(私はその1人です)、あなたのような人はあまりいません。 Symbolic Systems Program(SSP) at Stanford University を強くお勧めします。彼らのウェブサイトが言うように:

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

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

私は左のフィールドから少し何かを提案するつもりです: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プログラマーは必ずしも考慮していないという印象を受けます言語を拡張するということですが、Rubyでプログラミングする方法に過ぎません。

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

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

この調査的アプローチは、より正式なアプローチに適している可能性があります。これは、使用している言語で学習した概念を認識し始め、その逆も同様です。

楽しんで!

2
kindall

コンパイラがどのように機能するか、独自のプログラミング言語を作成する方法を簡単に紹介するには、新しい本http://createyourproglang.comをお勧めしますOS/CPUの内部、つまりレクサー、パーサー、インタープリターなどについて知る必要がない言語設計理論の詳細.

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

2
mythz

Kenneth Loudenの著書「コンパイラの構築」を参照してください。

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

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

人々は行うことによって学びます。ボード上に描かれたシンボルを確認して、理論から実践にすぐにジャンプできるのはごく少数です。残念ながら、それらの人々はしばしば独断的で原理主義者であり、それについて最も騒々しいです。

1
Jarvis Jones

さて、あなたの質問は「コンピュータサイエンスの学位の中心となる実用的な概念は何ですか」に書き換えられると思います。もちろん、完全な答えは、コンピュータサイエンスの学士号を取得することです。

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

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

アセンブラは、テキストからバイトへの変換です。

このことに興味がある場合は、標準のX86アセンブリのサブセットをサポートするLinuxでX86アセンブラを作成することをお勧めします。これはかなり簡単なエントリーポイントであり、これらの問題を紹介します。それは赤ちゃんのプロジェクトではなく、あなたに多くのことを教えます。

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

1
Paul Nathan

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

同じ啓示へのもう1つの入り口は、Knuthが彼の例で使用する「ミックス」アセンブリ言語です。 「ミックス」は今日古風に見えますが、それでもDEを神秘化する効果があります。

1
ddyer

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

まず、オペレーティングシステムの一般的な理解と、既存の言語のコンパイル/実行方法(ネイティブ(C/C++)、VM(Java)またはインタプリタ(Python/Javascript))。

私のオペレーティングシステムコース(2年目)では、Abraham Silberschatz、Peter B. Galvin、Greg Gagneの著書「Operating System Concepts」を使用したと思います。これは、オペレーティングシステムの各コンポーネントの完全なウォークスルーを提供する優れた本でした-少し高価ですが、それだけの価値があり、古い/使用済みのコピーが浮かんでいるはずです。

0
plafond

これは大きなトピックですが、「本を読んでください、子供だ」という派手な言葉に気を取られるのではなく、頭を抱えるのに役立つポインタを喜んで提供します。

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

Tokenize:コードテキストをスキャンして、トークンのリストに分割します。

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

Lex:これで、トークンのリストができました。最初のパスでは、各文字列のコンテキストを理解しようとする努力をあまりしなかったため、Wordのようなあいまいな分類でいくつかのトークンをタグ付けした可能性があります。ソーストークンのリストをもう一度読んで、言語のキーワードに基づいて、あいまいな各トークンをより具体的なトークンタイプに再分類してください。したがって、「if」などの単語があり、「if」がシンボルIFと呼ばれる特別なキーワードのリストにあるため、そのトークンのシンボルタイプをWordからIFに変更し、特別なキーワードリストにないすべてのWord Word fooなどのIDはIDENTIFIERです。

Parse:したがって、次のようなlexedトークンのリストを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()。

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

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

AST型がASIGN_ADDの部分を見てみましょう。インタプリタとしてASIGN_ADD_execute()関数があります。この関数はASTこれは_foo += "a string"_の解析ツリーに対応するため、この関数はその構造を調べ、構造の最初の項がIDENTIFIERである必要があることを認識し、2番目の項がVALUEであるため、ASIGN_ADD_execute()が渡されます評価された値を表すオブジェクトをメモリに返すVALUE_eval()関数のVALUE項。次にASIGN_ADD_execute()が変数テーブルで「foo」の検索を行い、eval_value()関数によって返されたものへの参照を格納します。 。

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

手順1〜3、およびいくつかの4は、FlexやBisonなどのツールを使用して簡単にできます。 (別名:LexとYacc)しかし、インタープリターを自分でゼロから作成することは、おそらくプログラマーが達成できる最も強力な練習です。他のすべてのプログラミングの課題は、これをサミットした後はささいなことのようです。

私のアドバイスは小さく始めます。小さな文法を備えた小さな言語で、いくつかの単純なステートメントを解析して実行し、そこから成長していきます。

これらを読んで、頑張ってください!

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

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

0
snorkel

コンピュータ分野は、多くの方向に進化する時間があるため、複雑なだけです。その中心にあるのは、計算を行うマシンです。

私のお気に入りの非常に基本的なコンピューターは ハリーポーターのリレーコンピューター です。これは、コンピューターが基本レベルでどのように機能するかを示します。次に、言語やオペレーティングシステムなどが必要な理由を理解し始めることができます。

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

0
Mike Dunlavey