自由帳

@_nibral の技術ブログ

Writing An Interpreter In Go その6

その5はこちら

Parserが構築した抽象構文木 (AST) を評価し、入力したソースコードの意味を取り出すEvaluatorの作成に入る。

3.4: オブジェクト表現を実装

3.4: Implement object representation · nibral/monkey_interpreter@ac2828d · GitHub

Evaluatorで評価した値を扱うためにObjectというインターフェースを定義する。実際の評価結果はIntegerだったりBooleanだったりNullだったりするが、これらを表す構造体に全てObjectインターフェースを実装することになる。

全てはObject、と言われるとC#っぽいなと思ったり。

3.5: Integerの評価

3.5: Evaluate integer · nibral/monkey_interpreter@e018d49 · GitHub

プログラムを1行ずつ取り出してASTを再帰的に辿っていき、一番末端の IntergerLiteral (Parserの表現) から object.Integer (Evaluatorの表現) を生成して評価値とする。あるブロックに含まれるプログラムが複数行ある場合、最後に評価した値が戻り値として扱われる。

対話コンソールにも改良を行い、単にASTを出力していたところを評価結果の出力に変更。

3.5: Booleanと前置演算子の評価

3.5: Evaluate boolean and prefix expressions · nibral/monkey_interpreter@fa18985 · GitHub

IntegerLiteral と同様に Boolean と PrefixExpression の評価を追加。真偽を反転する ! 演算子を扱うにあたって true/false以外の値(例えば整数の5)に対する挙動をどうするか決める必要があるが、Monkeyではtrueとして扱うことになっている。つまり、!5 は false として評価される。

また、Evaluator内部ではTrue,False,Nullを示すオブジェクトを区別する必要がないので、あらかじめオブジェクトを生成しておいて使いまわす。

3.5: 2項演算子の評価

3.5: Evaluate infix expressions · nibral/monkey_interpreter@d341f9e · GitHub

+,-,*,/,<,>,==,! の評価。

いまのところ評価できるのは整数と真偽値だけなので、演算子の両辺が整数なら整数用の評価処理、真偽値なら ==/!= の評価を行う。真偽値の評価はオブジェクトを共有していることが前提なので、整数のcaseより後に書く必要がある。

// case文をこの順番で書かないと正しく評価されない
switch {
case left.Type() == object.INTEGER_OBJ && right.Type() == object.INTEGER_OBJ:
    return evalIntegerInfixExpression(operator, left, right)
case operator == "==":
    return nativeBoolToBooleanObject(left == right)
case operator == "!=":
    return nativeBoolToBooleanObject(left != right)
default:
    return NULL
}

この時点で対話コンソールが電卓として使えるようになった。

> go run .\main.go
Hello nibral! This is the Monkey programming language!
Feel free to type commands
>> 2 + (3 * 4)
14
>> (1+2*3)==7
true
>>