私は自分の汎用の高水準プログラミング言語を書くことに本当に興味がありますが、少し混乱しています。
PythonとRubyはCで書かれていたので、自分の「Python」を書きたいのであれば、私の言語のすべてのソースコードをCに変換するためのソースからソースへのコンパイラ、またはアセンブリ言語をターゲットにする必要がありますか?
重要なのは、コンパイラの設計を掘り下げて字句解析を理解し、コードを解析してトークンと中間言語を生成し、構文エラーと意味エラーをチェックして出力コードを生成するプロセス全体を理解する必要があることです。
ただし、私は低レベル/アセンブリプログラミングの専門家ではないので、ソースからソースへのコンパイラを使用する必要がありますか?言語をアセンブリにコンパイルしようとすると、どのような課題に直面する可能性がありますか?ソースからソースへのコンパイラを使用する際にどのような欠点があるのでしょうか?この決定を行う際、私のドメイン固有の状況について検討する必要がありますか?
他のものが他の場所で回答されているので、私はあなたの中心的な質問に焦点を当てます。
より高いレベルの言語またはアセンブリをターゲットにする必要がありますか?
ソフトウェアを完成させるのは難しい。新しい言語の作成canは非常に簡単ですが、単純なものに固執し、実装が面倒なものを避ける必要があります。第一言語を作ることには、「実装するための痛み」が何であるかが分からないという問題があります。それに直面してみましょう。コンソールベースの計算機のみを実装できる新しい言語を作ることを目指していません。興味深いものは実装するのが簡単ではありません。
ですから、自分に有利にして、すでに知っている言語をターゲットにしてください。タスクのリストに「アセンブリの学習」を追加しない限り、新しい言語と関数型コンパイラを作成するのは十分に困難です。成功するために自分自身を設定することにより、楽しみを持ち、その努力から学ぶ可能性が高くなります。
C( this と that の回答を参照)、またはその他の言語(Java、Common LISP、Ocaml、またはJavaScriptとCのような [〜# 〜] hop [〜#〜] は...) [〜#〜] llvm [〜#〜] バイトコードのテキスト表現にコンパイルするか、バックエンドとしてLLVMライブラリを使用することもできます、または(GCC 5以上の場合) libgccjit を使用します(GCCの内部表現を対象とし、GCC最適化から利益を得ます)。既存の バイトコード (JVM、Ocaml、Neko、Parrotなど)を選択して、それにコンパイルすることもできます。また、libjit
、GNU lightning、asmjit
などのJITライブラリを使用することもできます...
Lexing & parsing はnotコンパイラーまたはインタープリターの主な作業です。これらは単純な部分です。コンパイラーはほとんどがtransforming(多くの場合、いくつかのパスで))コンパイルしているソースコードの内部表現(特に 抽象構文ツリー だけでなく)-インタープリターは、いくつかの内部表現を変換してから、他の内部表現(たとえば、いくつかのバイトコードやいくつかの正規化されたAST)をトラバースします。 [〜#〜] gcc [〜#〜] の-fdump-tree-all
オプションを使用して、おそらく [〜#〜] melt [〜#〜] (LISPのようなDSL GCCの内部表現を検査および/または変換します。プログラミング言語の セマンティクス は、構文よりも重要です。
重要な部分は メモリ管理 です。ガベージコレクターが必要ですか(それはセマンティクスのコアパーツです)? 型付け (静的または動的)& 型推論 はどうですか? 末尾呼び出し を処理しますか? 同音性 が欲しいですか? メタプログラミング ? クロージャ (たいていはGCが必要です)が必要ですか? Boehm's conservative GC を検討し、および/または GCハンドブック を読んでください。
ブートストラップ コンパイラ は 重要です。 this と私がそこで与えた参照も参照してください。また、 this & that は、技術的および実用的な詳細の説明に回答します(そして、「Haskellで書かれたHaskell」、「Ocamlで書かれたOcaml」、「MELTで書かれたMELT」、「CAIAで書かれた」に関する頭痛を癒す必要がありますCAIA」、「C++で記述されたGCCまたはClang/LLVM」)。
また、それらのいずれも知らない場合は、Ocaml、Common LISP、Haskell、またはSchemeで遊んでください( [〜#〜] sicp [〜#〜] も参照)。 Programming Language Pragmatics に関するスコットの本と LISP In Small Pieces に関するQueinnecの本を読んでください。
言語の実装を必ずいくつかにしてください フリーソフトウェア ( http://github.com/に コンパイラやインタープリターなど、他の多くの言語の実装があります)。
3年前に、リフレクションを使用して.NETインターフェイスを理解し、それを基本クラスに変換するCIL接着剤を提供する専門的な作業を行いました。必要な追加作業のレベルに目を見張るものでした。
ほとんどのソフトウェア開発では、成功ルートに焦点を当て、予期しないことが発生した場合は例外をキャッチします。成功ルートは作業の20%未満であることがわかりました。例外はコードを生成するときではなく実行時に発生するため、例外をキャッチする通常の戦略は機能しません。代わりに、コードを壊す可能性のある組み合わせを考えて確認し、それをサポートするか、コンパイルを失敗させる必要があります。これは、アプリケーション開発とは大きく異なります。
新しいプログラミング言語を作成し、他の言語で採用したい場合、最善の策は、現在簡単に解決できない問題を見つけることです。複雑な問題を解決するためのクリーンでシンプルなアプローチを提供する新しいプログラミング言語を作成する場合、その問題を持つ人々はあなたの言語を採用する十分な理由があります。
「自分で汎用の高水準プログラミング言語を書くことに本当に興味がある」本当ですか?本当に興味があり、(ネイティブ)コンパイラーで完全な独自の言語を作成して、アセンブリの読み取りとCPUの動作に興味があると思われる場合は、既存の高水準言語のアセンブリ出力を調べて、あなたにアイデアを与えます。
ネイティブマシンコードコンパイラのソースにより、言語のセマンティクスをより自由に定義できます。Cにコンパイルする場合、基本的にCの方法に限定されるため、最終的には適切なテールなどの機能を含めることができます。通話が届きません。ネイティブコンパイラの構築は、よりやりがいがあり、啓蒙的な経験になる可能性があります。一方、Cへのコンパイルは、基本的に誰か他のものを使用しています。構築されたCは、出力するものに対して非常に複雑な言語です(その構文は、人間が使いやすいように設計されていますマシンで生成するのは簡単ではありません)、宣言のネスト順について心配する必要があります。Cコンパイラがコードを効果的に最適化できるように十分な情報を指定する必要があります(たとえば、ポインターのエイリアスがない場合は制限を使用します)。
実用的で、近い将来使用される言語を構築したいが、コンパイラを構築することにあまり興味がない場合は、使用する言語で動作するコンパイラを用意する必要があるので、ソースからソースへの移行が適しています。ただし、言語が実質的にプリプロセッサになることに注意してください(実際、プリプロセッサは字句解析と構文解析について学ぶのに適した場所です)。どちらの方法でも、言語を配布することが目的である場合は、それがJAP言語(ちょうど別のプログラミング言語)にならないようにしてください。これは、新しいものを何も提供しない言語であり、既存の言語を大幅に改善するものではありません。
必要なものをすべてCに変換すると、Cコンパイラを利用できる場所であれば、システムが動作します。基本的にはどこにでもあります。異なるプロセッサ、異なるオペレーティングシステム、およびその他すべてについて心配する必要はありません。
代わりにC++にコンパイルすることもできます。今日はCと同じようにほぼであり、クラスで行う必要のある作業を繰り返す必要がなく、自分でやり直す必要がないという利点があります。言語にCまたはC++プリミティブに変換できないオブジェクトがある場合は重要です。