変数を追加しよう
変数定義と変数の使用が出来るようにしましょう。
構文解析
変数定義の構文解析
変数定義の文法を考えましょう。今回は次のような文法とします。
let (変数名)=(代入する式);
ここで、小文字の英字の1個以上の並びにマッチするプリミティブな文法のIdentを紹介します。
Ident = _ [a-z]+ { return text() }
次に、これをPEG.jsのコードに落とし込んでいきましょう。 どのようなASTを構築するかによって書き方が変化するのですが、今回は
let a=1;
let b=2;
a+b
のように、変数定義が複数あってから、式が来るようなプログラムが実行できるようにします。
example
start = Assign
Assign = "let " ident: Ident "=" e1: Expression ";" _ e2: Assign {
return {tag: "Assign", ident: ident, assign_expr: e1, value: e2}
} / Expression
変数の使用の構文解析
これは簡単ですね。Factorの末尾に追記しましょう。
Factor = ・・・
} / ident: Ident {
return {tag: "Variable", name: ident}
}
評価
変数を使ったプログラムを評価するには、変数の値を覚えておく必要があります。そのため、グローバル変数として環境をあらわすenvを用意します。
let env = {} // envは変数名と値の辞書とする
const eval = ・・・
さて、ast.tagが"Assign"の時にやるべきことは何でしょうか?評価規則を考えてみましょう。
let (変数名)=(代入する式); (後続の式)
まず、代入する式を評価します。そして、envに、(変数名)のときの値を登録します。その後、後続の式を評価します。 JavaScriptでの辞書への追加方法は以下の通りです。
env["a"] = 1
それでは、ast.tagが"Assign"のときの分岐を書いてみましょう。
example
case "Assign":
env[ast.ident] = eval(ast.assign_expr)
return eval(ast.value)
次に、変数を使用するための評価規則を追加します。ast.tagが"Variable"のastに出会ったときに、envからその変数の値を取り出します。
変数の使用
case "Variable":
return env[ast.name]
これで、変数を使ったプログラムが実行できるようになりました。実際に試してみましょう!