0

私はまだ学校のタスクで定義された小さな言語のための小さなパーサーに取り組んでいます。AST(抽象構文木)を生成するパーサーが機能しています。私が欲しいのは、定義された変数をチェックすることです。それらはlet式によって制限されなければなりません。まず、タスクで定義されているメソッド(提案、不要):

checkVars :: Expr -> Char 

data Expr =  Var Char | Tall Int | Sum Expr Expr | Mult Expr Expr | Neg Expr | Let Expr Expr Expr
    deriving(Eq, Show) 

有効な文は「*(2、X)でXを5にする」です。Xは通常Varであり、5は通常intです。そして最後はdataExprタイプの任意の部分にすることができます。要点:Xは最後の式のどこかで使用されています。letのデータ型は次のとおりです。

Let Expr Expr Expr

このタスクについて私が尋ねた他の質問へのリンクは、参考までにここにあります。 最初の質問 2番目の質問

ご覧のとおり、checkVarsのデータ型はExprであるため、その関数にフィードするものの例を次に示します。

parseProg "let X be 4 in let Y be *(2 , X) in let Z be +(Y , X) in
+(+(X , Y) , Z)"
Let (Var 'X') (Tall 4) (Let (Var 'Y') (Mult (Tall 2) (Var 'X')) (Let
(Var 'Z') (Sum (Var 'Y') (Var 'X')) (Sum (Sum (Var 'X') (Var 'Y')) (Var
'Z'))))
Just 24

これは包括的な例であり、上部は解析される文字列/プログラムです。3行目(Let)から始まる2番目の部分は、checkVars関数の入力であるASTです。そして下の部分「Just24」は評価です。私はもっ​​と助けを求めてここに戻ってきます。注:重要なのは、エラーとして最初に見つかったバインドされていない変数を吐き出すことです。すべてが正常な場合は''です。明らかに、これを別の方法で実行したい場合は、可能です。

4

2 に答える 2

5

考えるべきことがあります:

Letコンストラクターの最初のフィールドはExprです。しかし、それは実際にs以外のものを保持できVarますか?そうでない場合は、そのフィールドのタイプを作成し、Stringそれに応じてパーサーを適応させることによって、これを反映する必要があります。これにより、タスクがはるかに簡単になります。

(あなたがしている)let-bindingsで式を評価するための標準的なトリックは、関数を書くことです。

type Env = [(String, Int)]
eval :: Expr -> Env -> Int

環境に関する追加の引数に注意してください。環境は、任意の時点でどの変数がどの値にバインドされているかを追跡します。evalタイプ内でのその位置は、子式を呼び出すたびにその値を決定できることを意味します。これは非常に重要です。また、ローカルで宣言された変数を持つことができることも意味します。変数をバインドしても、そのコンテキストには影響せず、部分式にのみ影響します。

特殊なケースは次のとおりです。

  • で、環境内の変数名を指定し、それにバインドされている値を返しますVarlookup(標準のプレリュード機能を使用しますlookup。)
  • で、子式に渡す前に、環境リストの先頭にLetエクストラを追加します。(varname, value)

詳細は省略しましたが、これで十分です。行き詰まったら、別の質問をしてください。:-)

Maybeああ、失敗を示す値を返したいと思います。error最初に、バインドされていない変数を指定せずに使用して示すことをお勧めします。そのバージョンが機能している場合は、eval戻りMaybe値に合わせて調整します。この理由は、Maybe値を操作すると評価がかなり複雑になるためです。

于 2009-10-08T08:40:17.830 に答える
0

私は実際にASTを評価しようとします。すべてのを処理(したがって削除)することから始めLetます。次に、結果のASTを評価してみます。に遭遇した場合Var、バインドされていない変数があります。

于 2009-10-07T23:29:21.177 に答える