パーサーがASTを生成する方法を調査した結果、ASTを作成する試みを知ることができると思います。このプロジェクトを始める前に、自分の言語文法を表すASTを作成した後、次に何をすべきかについて考え始めました。このトピックについての研究にもかかわらず、私は品質に関するリソースを明らかにしていませんAST=ソースコードを実行するために何をすべきかを説明します。
たとえば、次の例を見てください。
var = 10 + 2
。
パーサーは、これに類似したASTを作成する場合があります。
=
/ \
var +
/ \
10 2
AST上記の例では、次に何が行われますか?パーサーは変数とその値を記録しますか?または、パーサーはASTを生成し、ASTを評価する他のプログラムまで。
ASTを作成すると、プログラムの残りの部分でより多くの作業ができるようになります。ASTを読み取るものはすべて、ステートメントとスコープ。トークンをステートメントにグループ化し、ASTなしで各ステートメントを個別に実行することは、意味がありませんか?
注:私の質問は ASTトランスレータを構築するのに十分ですか? 。その質問のOPはASTで言語機能を実装するのに十分ですか?。 ASTから言語のソースコードをどのように実行するのか質問しています。投稿の一部は似ているかもしれませんが、全体的な質問はそれぞれが非常に異なります。
パーサーは、コードを論理的に意味のある部分に分解するだけです。次に、解析結果で何かを行うのは次の処理ステップです。
次の手順(コードインタープリターの場合)では、セマンティクスに焦点を当てることができます。パーサーはすべての汚い作業を行い、その結果はクリーンでシンプルです。だから物事が簡単になります。テキストの一部(1つの文字列または行のコレクション)から始め、パーサーがオブジェクトモデルを提供することに注意してください。 AST、つまりコードでの実装に関してそれが何を意味するのかを明確に理解していないようです。それでは始めましょう。
実行エンジンはツリーを読み取り、1つのオブジェクト、つまり割り当てを見つけます。割り当てクラスには、leftとrightの2つのプロパティが含まれています。左は変数オブジェクト、右は式オブジェクトです。
式オブジェクトもツリーであり、基本的には他のオブジェクトを含む一連のオブジェクトです。これらは通常、再帰的に処理されます。プロセッサーは、ツリーの深さを知らないか気にしない最初のオブジェクトにヒットするため、その1つのオブジェクトを処理し、含まれているオブジェクトの処理を同じコードに委任します。そのコードが葉(オブジェクトではない、複雑ではないオブジェクト)にヒットすると、アクションを実行するか、結果を返します。次に、最上位のオブジェクトがその結果を取得して処理を実行できるようになるまで、すべてがコールスタックにバブリングします。この例では、10と2を加算します。
簡単にできるのは、ネストされたオブジェクトのコレクションを調べて再帰的に解決できることです。テキストを解析してそれを一度に実行すると、すぐに面倒になり、構文エラーがさらに発生し、すでに実行を開始しているため、中途半端な結果になる可能性があります。
パーサーは変数とその値を記録しますか?
いいえ。パーサーはトークンを受け取り、それらをAST(おそらくエラーを返す)に配置します。
トークンをステートメントにグループ化し、各ステートメントをASTなしで個別に実行することは、意味がありませんか?
あんまり。 ASTを使用すると、プログラムを構成要素に分解し、それらの小さなシンプルな部分をエラーのない明確な方法で実装できます。さらに良いことに、不可知論的な方法です。ASTを使用して静的分析を行う場合は、できます。そのASTを使用して実行する場合インタプリタであれば、インタプリタは結合性について、またはステートメントが適切に解析されるかどうか、またはその識別子が実際に何を参照しているかについて心配する必要はありません。ASTを取得して、いくつかに対してコンパイルする場合AST=の小さなノードがそのプロセッサの新しいアセンブリと整列している可能性が高いため、新しいプロセッサを使用できます。
あなたcanインタープリターまたはコンパイラーを作成するときにASTを構築することを避けますが、私はそれをお勧めしません。そして、それを実行可能なものに変える方法はあなた次第ですただし、パーサーの出力が単純なツリー形式であれば、実装がはるかに簡単になります。