7

私はすでに取り組んでいる言語のパーサーを持っています。解釈させるのは難しいですか?シンプルに考えていました。解析と構文チェックが行われます。私はちょうどオブジェクトのツリーを持っています。オブジェクトが作成されるたびにブランチを作成し、その型 (string、int、float、class/obj) を保存します。次に、新しいメンバーがオブジェクトに追加されるたびに、ブランチを作成して繰り返します。

シンプルに聞こえるようにしています。オブジェクトAをオブジェクトBなどに追加できるかどうかを確認する必要があります。

AST と構文チェックが完了した後は、実際にはかなり単純ですか、それともまだ多くの作業がありますか?

4

3 に答える 3

5

通常、シンボル テーブルを作成し、型チェックを行う必要があります。一部の言語では、これをオンザフライで行うことができます。他の人にとっては、ほとんど最初に名前解決と型チェックを行う必要があると思います。そうしないと、うまく解釈できなくなります (C++ が思い浮かびます)。

シンボル テーブルを作成したら、ツリーを実行順にたどり、演算子の言うことを実行することで、ほとんどのインタプリタを作成できます。基本的な算数はとても簡単です。文字列と動的ストレージの管理はより困難です。ストレージの割り当てと割り当て解除をどのように処理するかを理解する必要があり、ストレージを管理する言語では、何らかのガベージ コレクターを実装する必要があります。この時点で、人生は急速に複雑になります。

あなたの言語があなたが考慮していなかった機能を必要としていることに気付くでしょう。例外処理?複数の任務?ローカルスコープ?ラムダ?閉鎖?現代の言語がどれだけ有用な機能を持っているかすぐにわかるでしょう。

より複雑なプログラムを書き始めると、デバッガーが必要になります。ブレークポイント?単一段階?可変検査?アップデート?任意の場所から開始しますか? 読み取り-評価-印刷ループ?

言語を外部ライブラリに結び付ける必要があります。ほとんどの人は、コンソールやファイルと対話したいと考えています。バッファリングされたファイルが必要ですか、それとも一度に 1 文字で対応するパフォーマンス ヒットで問題ありませんか? 文字表現 (7 ビット ascii? 8 ビット? 非ユニット ワイド文字を含む UTF8? 完全な Unicode?) と標準サポート ライブラリ (文字列連結、検索、数値変換 [双方向の正確な浮動小数点変換を含む]) について議論するようになります。 、大数演算、浮動小数点トラップ、.... 便利なプログラミング言語が必要な場合、問題のリストはかなり長くなります。

インタプリタのコアはおそらくかなり小さいでしょう。他のものは、おそらく 1 ~ 2 桁多くの労力を費やすことがわかります。このどこかで、誰かにその言語を使ってもらいたい場合は、行ったすべての選択を文書化する必要があります。そして、誰かが大きなアプリケーションを実行した後にインタープリターを少し変更すると、天国が助けてくれます。

次に、誰かがパフォーマンスについて文句を言うでしょう。これで実装を調整できるようになり、コンパイラーではなくインタープリターを作成したことを後悔し始めます。

楽しみ。AST をお持ちの場合は、表面をかじっただけです。これを実践すれば、現代の言語がすぐに提供するものと、それを提供するのにどれだけの労力がかかったのかを本当に理解することを学ぶでしょう.

于 2011-02-16T03:07:29.040 に答える
3

それは、インタープリターを作成する言語の複雑さと、ツールの選択によって異なります。シンプルなインタープリターはシンプルです。

高階関数と数値をサポートする言語の Haskell での AST の定義として、以下を検討してください。

data Exp = Lam String Exp 
         | App Exp Exp 
         | Var String 
         | Num Int

これで、単純な「eval」関数としてインタープリターを作成できます。

eval (App e1 e2) env = (unF (eval e1 env)) (eval e2 env)
eval (Lam x e) env   = F (\v -> (eval e ((x,v):env)))
eval (Num n) env     = N n
eval (Var x) env     = case (lookup x env) of 
                         Just v -> v
                         Nothing -> error ("Unbound variable " ++ x)

以上です。いくつかの退屈なサポート定義は次のとおりです。

data Val = F (Val -> Val)  | N Int
unF (F x) = x
instance Show Val where 
    show (F _) = "<procedure>"
    show (N n) = show n

つまり、上記の 3 つのコード ブロックを Haskell ソース ファイルにコピー ペーストすると、次のように ghci を使用してテストできる、動作するインタープリターが作成されます。

*Main> eval (App (Lam "x" (Var "x")) (Num 1)) []
1
*Main> eval (Var "x") []
*** Exception: Unbound variable x

古典的なSICPEOPL、または小さな本で言語の作成について読むことができます。型付き言語を構築したい場合は、さらに読む必要があるかもしれません。

そうは言っても、言語を構築する場合は、最初にたくさん読むことを強くお勧めします. 一つには、非常にやりがいがあります。そして第二に、言語の作成方法を知らない人々によってあまりにも多くの恐ろしい言語が世界にもたらされており (その多くは、さまざまな歴史的理由から非常に人気が高まっています)、私たちはそれらに行き詰まっています.

于 2011-02-16T04:23:17.123 に答える
0

ASTを行った後、難しい部分(そして実際には最も面白い部分)が始まると思います。

LLVMを見てください。LLVMには多くの言語のバインディングがあり(私はC ++とHaskellのみを使用しましたが、他の言語についてはわかりません)、ご使用の言語のジャストインタイムコンパイラーを作成するのに役立ちます。実際、LLVMを使用すると、インタープリターよりもコンパイラーを簡単に作成できます。

于 2011-02-15T19:44:07.910 に答える