前回はクロージャを使って「連結リスト」を実装しました。今回は電卓プログラムに新しいデータ型として「連結リスト」を追加してみましょう。
最初に連結リストを表すデータ型を定義します。次のリストを見てください。
リスト : 連結リストの定義
// セル
type Cell struct {
car, cdr Value
}
// セルの生成
func newCell(a, b Value) *Cell {
return &Cell{a, b}
}
// 空リスト
var NIL *Cell
// NIL の初期化
func makeNIL() {
NIL = newCell(nil, nil)
NIL.car = NIL
NIL.cdr = NIL
globalEnv["nil"] = NIL
}
// Value の実装
func (x *Cell) isTrue() bool { return x != NIL }
セルは構造体 Cell で表します。フィールド変数は car と cdr で、どちらも型は Value です。関数 newCell は新しいセルを作ります。大域変数 NIL は空リスト (nil) を表します。NIL の初期化は関数 makeNIL で行います。NIL の car と cdr は自分自身の値で初期化します。そして、大域変数 globalEnv に変数 nil を追加します。
セル (*Cell) は値 (Value) として扱うので、メソッド isTrue を定義します。このとき、空リスト (NIL) は偽と判定し、それ以外は真と判定します。リストを操作するプログラムでは、空リストを偽と判定したほうが都合がよい場合があります。
関数 null, pair, eql, car, cdr, cons, setCar, setCdr は組み込み関数として定義します。それから、連結リストを生成する構文としてリスト生成式を定義します。リスト生成式の構文は次のようになります。
list(引数1, ..., 引数n)
list は複数の引数を評価して、その結果を連結リストに格納して返します。これは Lisp / Scheme の関数 list と同じ働きをします。電卓プログラムの関数には可変個引数の機能がないので、構文で list を用意しました。トークンに LIST を追加し、keyTable["list"] に LIST を追加します。
次は値 (Value) を文字列に変換する関数 sprintValue を作ります。
リスト : 値を文字列に変換
// リスト -> 文字列
func sprintlist(cp *Cell) string {
s := "("
for cp != NIL {
s += sprintValue(cp.car)
b, ok := cp.cdr.(*Cell)
if ok {
cp = b
if cp != NIL { s += " " }
} else {
s += " . " + sprintValue(cp.cdr)
break
}
}
s += ")"
return s
}
// Vec -> string
func sprintvec(xs Vec) string {
s := "["
i := 0
for ; i < len(xs) - 1; i++ {
s += sprintValue(xs[i]) + ", "
}
s += sprintValue(xs[i]) + "]"
return s
}
// Value -> string
func sprintValue(v Value) string {
switch x := v.(type) {
case *Cell: return sprintlist(x)
case Vec: return sprintvec(x)
default: return fmt.Sprint(x)
}
}
連結リストはベクタの中に格納できるので、ベクタを文字列に変換する処理も作ります。printValue は型 switch で引数 v の型を判定し、セル (*Cell) であれば、関数 sprintlist を呼び出します。連結リストは、前回と同じく Lisp / Scheme の表記法に従います。処理内容も前回の関数 printlist とほとんど同じなので、説明は割愛します。
ベクタ (Vec) の場合は関数 sprintvec を呼び出します。ベクタの表記法は [ ] で囲み、要素をカンマ ( , )で区切ります。あとは、ベクタの要素を順番に sprintValue で文字列に変換するだけです。連結リストとベクタ以外の場合は fmt.Sprint で文字列に変換します。それから、組み込み関数 print で、sprintValue の返り値を表示するように変更します。toplevel で値を表示する場合も、関数 print を呼び出すように変更します。
次は連結リストの基本関数を定義します。
リスト : 連結リストの操作関数
// 等値の判定
func eql(x, y Value) Value {
switch a := x.(type) {
case Func: return Int(0)
case Vec: return Int(0)
default: return boolToValue(a == y)
}
}
// コンスセルか
func pair(v Value) Value {
_, ok := v.(*Cell)
return boolToValue(ok && v != NIL)
}
// 空リストか
func null(v Value) Value {
return boolToValue(v == NIL)
}
// コンスセルの生成
func cons(x, y Value) Value {
return newCell(x, y)
}
// 先頭要素を取り出す
func car(v Value) Value {
cp, ok := v.(*Cell)
if !ok {
panic(fmt.Errorf("car: List required, %v", v))
}
return cp.car
}
// 先頭要素を取り除く
func cdr(v Value) Value {
cp, ok := v.(*Cell)
if !ok {
panic(fmt.Errorf("cdr: List required, %v", v))
}
return cp.cdr
}
// CAR 部を書き換える
func setCar(v, x Value) Value {
cp, ok := v.(*Cell)
if !ok {
panic(fmt.Errorf("setCar: List required, %v", v))
}
cp.car = x
return x
}
// CDR 部を書き換える
func setCdr(v, x Value) Value {
cp, ok := v.(*Cell)
if !ok {
panic(fmt.Errorf("setCdr: List required, %v", v))
}
cp.cdr = x
return x
}
func initFunc() {
・・・省略・・・
funcTable["eql"] = FuncV2(eql)
funcTable["pair"] = FuncV1(pair)
funcTable["null"] = FuncV1(null)
funcTable["cons"] = FuncV2(cons)
funcTable["car"] = FuncV1(car)
funcTable["cdr"] = FuncV1(cdr)
funcTable["setCar"] = FuncV2(setCar)
funcTable["setCdr"] = FuncV2(setCdr)
}
eql は Go 言語の演算子 == で比較します。インターフェースを == で比較する場合、実体の型と値が同じ場合は真 (1) を返し、そうでなければ偽 (0) を返します。ただし、関数とスライスは == で比較できないので、無条件で偽を返しています。セル (*Cell) はポインタなので、同じポインタであれば真を返すことになります。たとえば、eql(nil, nil) は真となります。
空リスト (NIL) の car と cdr は自分自身の値がセットされているので、関数 car と cdr に nil を渡すと、返り値は nil になることに注意してください。それ以外はとくに難しいところはないと思います。
次は連結リストを生成するリスト生成式の処理を追加します。構文解析は次のようになります。
リスト : リスト生成式の追加
func factor(lex *Lex) Expr {
・・・省略・・・
case LIST:
lex.getToken()
if lex.Token == '(' {
return newList(getArgs(lex))
}
panic(fmt.Errorf("List: '(' expected"))
・・・省略・・・
default:
panic(fmt.Errorf("unexpected token: %v", lex.TokenText()))
}
}
関数 factor でトークンが LIST の場合、次のトークンが '(' であることを確認します。そうでなければエラーを送出します。次に、getArgs でカッコの中の式を取り出し、それを関数 newList に渡し、リストの生成を表す構造体 List に格納して返します。
連結リストを生成する List の処理も簡単です。次のリストを見てください。
リスト : 連結リストの生成
// リストの生成
type List struct {
xs []Expr
}
func newList(xs []Expr) *List {
return &List{xs}
}
func (x *List) Eval(env *Env) Value {
cp := NIL
for i := len(x.xs) - 1; i >= 0; i-- {
cp = newCell(x.xs[i].Eval(env), cp)
}
return cp
}
式を格納したスライス x.xs の末尾から式を取り出して Eval で評価し、その結果を newCell で変数 cp の先頭に追加するだけです。
最後に、次に示す組み込み関数を追加します。
clock() => 現在時刻を整数で返す since(t) => 現在時刻と引数 t との差を文字列に変換して返す input(prompt) => prompt を表示して、標準入力から式を入力する error(err) => エラーを送出する
プログラムは次のようになります。
リスト : 組み込み関数の追加
// 時間
func clock() Value {
return Int(time.Now().UnixNano())
}
func since(v Value) Value {
x, ok := v.(Int)
if !ok {
panic(errorInt("since: ", v))
}
y := time.Now().UnixNano()
return Str(time.Duration(y - int64(x)).String())
}
// エラー
func userError(v Value) Value {
panic(fmt.Errorf("%v", v))
}
// 式の入力
func input(mes Value) Value {
var lex Lex
lex.Init(os.Stdin)
print(mes)
lex.getToken()
e := expression(&lex)
return e.Eval(nil)
}
clock は time.Now() で現在時刻を求め、UnixNano() で数値 (int64) に変換します。単位はナノ秒になります。since は引数 x と現在時刻 y の差を求め、それを time.Duration に型変換して、さらに String() で文字列に変換します。error は panic でエラーを送出するだけです。input は Lex (Scanner) を用意して、標準入力から expression で式を読み取り、それを Eval で評価して、その結果を返します。
あとの修正は簡単なので説明は割愛します。詳細はプログラムリストをお読みください。
それでは簡単な実行例を示します。
Calc> a = cons(1, 2); (1 . 2) Calc> pair(a); 1 Calc> car(a); 1 Calc> cdr(a); 2 Calc> setCar(a, 10); 10 Calc> a; (10 . 2) Calc> setCdr(a, 20); 20 Calc> a; (10 . 20) Calc> b = list(1, 2, 3, 4, 5); (1 2 3 4 5)
基本関数と list は正常に動作していますね。
前回作成した連結リストライブラリは、nil, null, pair, eql, car, cdr, cons, setCar, setCdr, printlist の定義を削除するだけで、そのまま利用することができます。
簡単な実行例を示します。
Calc> a = iota(1, 8); (1 2 3 4 5 6 7 8) Calc> b = iota(11, 18); (11 12 13 14 15 16 17 18) Calc> c = zip(a, b); ((1 . 11) (2 . 12) (3 . 13) (4 . 14) (5 . 15) (6 . 16) (7 . 17) (8 . 18)) Calc> flatten(c); (1 11 2 12 3 13 4 14 5 15 6 16 7 17 8 18) Calc> map(car, c); (1 2 3 4 5 6 7 8) Calc> map(cdr, c); (11 12 13 14 15 16 17 18) Calc> append(a, b); (1 2 3 4 5 6 7 8 11 12 13 14 15 16 17 18) Calc> d = list(5, 6, 4, 7, 3, 8, 2, 9, 1); (5 6 4 7 3 8 2 9 1) Calc> mergeSort(d, 9, fn(x, y) x < y end); (1 2 3 4 5 6 7 8 9) Calc> mergeSort(d, 9, fn(x, y) x > y end); (9 8 7 6 5 4 3 2 1) Calc> permutation(println, 3, list(1,2,3)); (1 2 3) (1 3 2) (2 1 3) (2 3 1) (3 1 2) (3 2 1) 0 Calc> nreverse(a); (8 7 6 5 4 3 2 1) Calc> a; (1)
正常に動作していますね。次は組み込み関数を試してみましょう。
Calc> def tak(x, y, z) if x <= y then z
else tak(tak(x - 1, y, z), tak(y - 1, z, x), tak(z - 1, x, y)) end end
tak
Calc> let s = clock() in tak(10, 5, 0), since(s) end;
4.516601ms
Calc> let s = clock() in tak(12, 6, 0), since(s) end;
23.216099ms
Calc> let s = clock() in tak(14, 7, 0), since(s) end;
132.5691ms
Calc> let s = clock() in tak(16, 8, 0), since(s) end;
789.037915ms
Calc> let s = clock() in tak(18, 9, 0), since(s) end;
4.930726623s
Calc> error("oops!");
oops!
Calc> input(">>> ");
>>> 100;
100
Calc> input(">>> ");
>>> 1 + 2 * 3;
7
Calc> input(">>> ");
>>> [1,2,3,4,5];
[1, 2, 3, 4, 5]
Calc> input(">>> ");
>>> "hello, world";
hello, world
Calc> input(">>> ");
>>> list(1,2,3,4,5);
(1 2 3 4 5)
実行環境: Julia 1.23.2, Ubunts 22.04 (WSL2), Intel Core i5-6200U 2.30GHz
tak は「たらいまわし関数」といいます。引数の与え方によっては実行に時間がかかるため、Lisp などのベンチマークに利用されることがあります。結果を見ると、電卓プログラムの実行時間は遅いですね。最適化は一切やっていないので、実行時間が遅いのは仕方がないでしょう。input は式を読み込むので、最後にセミコロンが必要になります。もちろん、文字列、ベクタ、リストも入力することができます。興味のある方はいろいろ試してみてください。
今回はここまでです。次回は電卓プログラム用の簡単なライブラリを作ってみましょう。
//
// calc8.go : 電卓プログラム (連結リストを追加)
//
// Copyright (C) 2014-2021 Makoto Hiroi
//
package main
import (
"fmt"
"os"
"math"
"time"
"text/scanner"
)
// キーワード
const (
DEF = -(iota+10)
END
IF
THEN
ELSE
NOT
AND
OR
EQ
NE
LT
GT
LE
GE
BGN
WHL
DO
LET
IN
FN
CALL
LIST
)
// キーワード表
var keyTable = make(map[string]rune)
func initKeyTable() {
keyTable["def"] = DEF
keyTable["end"] = END
keyTable["if"] = IF
keyTable["then"] = THEN
keyTable["else"] = ELSE
keyTable["and"] = AND
keyTable["or"] = OR
keyTable["not"] = NOT
keyTable["begin"] = BGN
keyTable["while"] = WHL
keyTable["do"] = DO
keyTable["let"] = LET
keyTable["in"] = IN
keyTable["fn"] = FN
keyTable["call"] = CALL
keyTable["list"] = LIST
}
// 値
type Value interface {
isTrue() bool
}
// 変数
type Variable string
// 局所変数の環境
type Env struct {
name Variable
val Value
next *Env
}
// 構文木
type Expr interface {
Eval(*Env) Value
}
// 数
type Num interface {
Value
Expr
neg() Value
sign() int
add(Value) Value
sub(Value) Value
mul(Value) Value
div(Value) Value
}
// 比較
type Cmp interface {
compare(Value) int
}
//
// 数値
//
type Int int64
type Flt float64
// エラー
func errorNum(mes string, v Value) error {
return fmt.Errorf("%sNumber required, %v", mes, v)
}
func errorInt(mes string, v Value) error {
return fmt.Errorf("%sInteger required, %v", mes, v)
}
// Value の実装
func (n Int) isTrue() bool { return n != 0 }
func (n Flt) isTrue() bool { return n != 0.0 }
// Expr の実装
func (e Int) Eval(_ *Env) Value { return e }
func (e Flt) Eval(_ *Env) Value { return e }
// 符号の反転
func (n Int) neg() Value { return -n }
func (n Flt) neg() Value { return -n }
// 符号を求める
func (n Int) sign() int {
switch {
case n > 0: return 1
case n < 0: return -1
default: return 0
}
}
func (n Flt) sign() int {
switch {
case n > 0.0: return 1
case n < 0.0: return -1
default: return 0
}
}
// 四則演算
func (n Int) add(x Value) Value {
switch m := x.(type) {
case Int: return n + m
case Flt: return Flt(n) + m
}
panic(errorNum("+, ", x))
}
func (n Flt) add(x Value) Value {
switch m := x.(type) {
case Int: return n + Flt(m)
case Flt: return n + m
}
panic(errorNum("+, ", x))
}
func (n Int) sub(x Value) Value {
switch m := x.(type) {
case Int: return n - m
case Flt: return Flt(n) - m
}
panic(errorNum("-, ", x))
}
func (n Flt) sub(x Value) Value {
switch m := x.(type) {
case Int: return n - Flt(m)
case Flt: return n - m
}
panic(errorNum("-, ", x))
}
func (n Int) mul(x Value) Value {
switch m := x.(type) {
case Int: return n * m
case Flt: return Flt(n) * m
}
panic(errorNum("*, ", x))
}
func (n Flt) mul(x Value) Value {
switch m := x.(type) {
case Int: return n * Flt(m)
case Flt: return n * m
}
panic(errorNum("*, ", x))
}
func (n Int) div(x Value) Value {
switch m := x.(type) {
case Int: return n / m
case Flt: return Flt(n) / m
}
panic(errorNum("/, ", x))
}
func (n Flt) div(x Value) Value {
switch m := x.(type) {
case Int: return n / Flt(m)
case Flt: return n / m
}
panic(errorNum("/, ", x))
}
// Cmp の実装
func (n Int) compare(x Value) int {
switch m := x.(type) {
case Int: return (n - m).sign()
case Flt: return (Flt(n) - m).sign()
}
panic(errorNum("compare, ", x))
}
func (n Flt) compare(x Value) int {
switch m := x.(type) {
case Int: return (n - Flt(m)).sign()
case Flt: return (n - m).sign()
}
panic(errorNum("compare, ", x))
}
//
// 文字列
//
type Str string
// エラー
func errorStr(mes string, v Value) error {
return fmt.Errorf("%sString required, %v", mes, v)
}
// Value, Expr, Cmp の実装
func (_ Str) isTrue() bool { return true }
func (s Str) Eval(_ *Env) Value { return s }
func (n Str) compare(x Value) int {
m, ok := x.(Str)
if !ok {
panic(errorStr("compare, ", x))
}
switch {
case n > m: return 1
case n < m: return -1
default: return 0
}
}
//
// 配列
//
type Vec []Value
// エラー
func errorVec(mes string, v Value) error {
return fmt.Errorf("%sVector required , %v", mes, v)
}
// Value の実装
func (_ Vec) isTrue() bool { return true }
// ベクタ生成用構文木
type Crv struct {
xs []Expr
}
func newCrv(xs []Expr) *Crv {
return &Crv{xs}
}
// ベクタの生成
func (a *Crv) Eval(env *Env) Value {
v := make(Vec, len(a.xs))
for i := 0; i < len(a.xs); i++ {
v[i] = a.xs[i].Eval(env)
}
return v
}
// ベクタの参照
type Ref struct {
name Variable
idxs []Expr
}
func newRef(name Variable, idxs []Expr) *Ref {
return &Ref{name, idxs}
}
// アクセス位置を求める
func getPos(a *Ref, env *Env) *Value {
v := a.name.Eval(env)
for k := 0; ; k++ {
xs, ok := v.(Vec)
if !ok {
panic(errorVec("", v))
}
y := a.idxs[k].Eval(env)
i := toInt(y)
if j := int(i); j < 0 || j >= len(xs) {
panic(fmt.Errorf("Out of Range, %v, %v", xs, j))
} else if k == len(a.idxs) - 1 {
return &xs[j]
} else {
v = xs[j]
}
}
}
// 評価
func (a *Ref) Eval(env *Env) Value {
return *getPos(a, env)
}
// ベクタの更新
type Udt struct {
ref *Ref
val Expr
}
func newUdt(ref *Ref, val Expr) *Udt {
return &Udt{ref, val}
}
// 評価
func (a *Udt) Eval(env *Env) Value {
x := getPos(a.ref, env)
v := a.val.Eval(env)
*x = v
return v
}
//
// 連結リスト
//
type Cell struct {
car, cdr Value
}
func newCell(a, b Value) *Cell {
return &Cell{a, b}
}
// 空リスト
var NIL *Cell
// NIL の初期化
func makeNIL() {
NIL = newCell(nil, nil)
NIL.car = NIL
NIL.cdr = NIL
globalEnv["nil"] = NIL
}
// Value の実装
func (x *Cell) isTrue() bool { return x != NIL }
// リストの生成
type List struct {
xs []Expr
}
func newList(xs []Expr) *List {
return &List{xs}
}
func (x *List) Eval(env *Env) Value {
cp := NIL
for i := len(x.xs) - 1; i >= 0; i-- {
cp = newCell(x.xs[i].Eval(env), cp)
}
return cp
}
// リスト -> 文字列
func sprintlist(cp *Cell) string {
s := "("
for cp != NIL {
s += sprintValue(cp.car)
b, ok := cp.cdr.(*Cell)
if ok {
cp = b
if cp != NIL { s += " " }
} else {
s += " . " + sprintValue(cp.cdr)
break
}
}
s += ")"
return s
}
// Vec -> string
func sprintvec(xs Vec) string {
s := "["
i := 0
for ; i < len(xs) - 1; i++ {
s += sprintValue(xs[i]) + ", "
}
s += sprintValue(xs[i]) + "]"
return s
}
// Value -> string
func sprintValue(v Value) string {
switch x := v.(type) {
case *Cell: return sprintlist(x)
case Vec: return sprintvec(x)
default: return fmt.Sprint(x)
}
}
//
// 変数と環境
//
// 環境の生成
func newEnv(name Variable, val Value, env *Env) *Env {
return &Env{name, val, env}
}
func makeBinding(xs []Variable, es []Expr, env *Env) *Env {
var env1 *Env
for i := 0; i < len(xs); i++ {
env1 = newEnv(xs[i], es[i].Eval(env), env1)
}
return env1
}
// 局所変数を環境に追加
func addBinding(xs []Variable, es []Expr, env *Env) *Env {
for i := 0; i < len(xs); i++ {
env = newEnv(xs[i], es[i].Eval(env), env)
}
return env
}
// クロージャ用
func addBindingClo(xs []Variable, es []Expr, env, clo *Env) *Env {
for i := 0; i < len(xs); i++ {
clo = newEnv(xs[i], es[i].Eval(env), clo)
}
return clo
}
// 局所変数の探索
func lookup(name Variable, env *Env) (Value, bool) {
for ; env != nil; env = env.next {
if name == env.name {
return env.val, true
}
}
return Int(0), false
}
// 局所変数の更新
func update(name Variable, val Value, env *Env) bool {
for ; env != nil; env = env.next {
if name == env.name {
env.val = val
return true
}
}
return false
}
// 大域的な環境
var globalEnv = make(map[Variable]Value)
// 変数の評価
func (v Variable) Eval(env *Env) Value {
// 局所変数の探索
val, ok := lookup(v, env)
if ok {
return val
}
// 大域変数の探索
val, ok = globalEnv[v]
if !ok {
panic(fmt.Errorf("unbound variable, %v", v))
}
return val
}
//
// 単項演算子
//
type Op1 struct {
code rune
expr Expr
}
func newOp1(code rune, e Expr) Expr {
return &Op1{code, e}
}
// bool を Value に変換する
func boolToValue(x bool) Value {
if x {
return Int(1)
} else {
return Int(0)
}
}
// 型変換とチェック
func toNum(v Value) Num {
n, ok := v.(Num)
if !ok {
panic(errorNum("", v))
}
return n
}
// 評価
func (e *Op1) Eval(env *Env) Value {
v := e.expr.Eval(env)
switch e.code {
case '-': return toNum(v).neg()
case '+': return v
case NOT: return boolToValue(!v.isTrue())
default:
panic(fmt.Errorf("invalid Op1 code"))
}
}
//
// 二項演算子
//
type Op2 struct {
code rune
left, right Expr
}
func newOp2(code rune, left, right Expr) Expr {
return &Op2{code, left, right}
}
// 型変換とチェック
func toInt(v Value) Int {
n, ok := v.(Int)
if !ok {
errorInt("", v)
}
return n
}
func toCmp(v Value) Cmp {
n, ok := v.(Cmp)
if !ok {
panic(fmt.Errorf("%v is uncomparable type", v))
}
return n
}
// 評価
func (e *Op2) Eval(env *Env) Value {
x := e.left.Eval(env)
y := e.right.Eval(env)
switch e.code {
case '+': return toNum(x).add(y)
case '-': return toNum(x).sub(y)
case '*': return toNum(x).mul(y)
case '/': return toNum(x).div(y)
case '%': return toInt(x) % toInt(y)
case EQ: return boolToValue(toCmp(x).compare(y) == 0)
case NE: return boolToValue(toCmp(x).compare(y) != 0)
case LT: return boolToValue(toCmp(x).compare(y) < 0)
case GT: return boolToValue(toCmp(x).compare(y) > 0)
case LE: return boolToValue(toCmp(x).compare(y) <= 0)
case GE: return boolToValue(toCmp(x).compare(y) >= 0)
default:
panic(fmt.Errorf("invalid Op2 code"))
}
}
//
// 短絡演算子
//
type Ops struct {
code rune
left, right Expr
}
func newOps(code rune, left, right Expr) Expr {
return &Ops{code, left, right}
}
// 評価
func (e *Ops) Eval(env *Env) Value {
x := e.left.Eval(env)
switch e.code {
case AND:
if x.isTrue() {
return e.right.Eval(env)
}
return x
case OR:
if x.isTrue() {
return x
}
return e.right.Eval(env)
default:
panic(fmt.Errorf("invalid Ops code"))
}
}
//
// if
//
type Sel struct {
testForm, thenForm, elseForm Expr
}
func newSel(testForm, thenForm, elseForm Expr) *Sel {
return &Sel{testForm, thenForm, elseForm}
}
func (e *Sel) Eval(env *Env) Value {
if e.testForm.Eval(env).isTrue() {
return e.thenForm.Eval(env)
}
return e.elseForm.Eval(env)
}
//
// while
//
type Whl struct {
testForm, body Expr
}
func newWhl(testForm, body Expr) *Whl {
return &Whl{testForm, body}
}
func (e *Whl) Eval(env *Env) Value {
for e.testForm.Eval(env).isTrue() {
e.body.Eval(env)
}
return Int(0)
}
//
// begin
//
type Bgn struct {
body []Expr
}
func newBgn(xs []Expr) *Bgn {
return &Bgn{xs}
}
func (e *Bgn) Eval(env *Env) Value {
var r Value
for _, expr := range e.body {
r = expr.Eval(env)
}
return r
}
//
// let
//
type Let struct {
vars []Variable
vals []Expr
body Expr
}
func newLet(vars []Variable, vals []Expr, body Expr) *Let {
return &Let{vars, vals, body}
}
func (e *Let) Eval(env *Env) Value {
return e.body.Eval(addBinding(e.vars, e.vals, env))
}
//
// 代入演算子
//
type Agn struct {
name Variable
expr Expr
}
func newAgn(v Variable, e Expr) *Agn {
return &Agn{v, e}
}
func (a *Agn) Eval(env *Env) Value {
val := a.expr.Eval(env)
if !update(a.name, val, env) {
globalEnv[a.name] = val
}
return val
}
//
// 関数
//
//
// 関数
//
type Func interface {
Value
Expr
Argc() int
}
type Func1 func(float64) float64
func (f Func1) Argc() int { return 1 }
func (f Func1) isTrue() bool { return true }
func (f Func1) Eval(_ *Env) Value { return f }
func (f Func1) String() string { return "<Function1>" }
type Func2 func(float64, float64) float64
func (f Func2) Argc() int { return 2 }
func (f Func2) isTrue() bool { return true }
func (f Func2) Eval(_ *Env) Value { return f }
func (f Func2) String() string { return "<Function2>" }
type FuncV0 func() Value
func (f FuncV0) Argc() int { return 0 }
func (f FuncV0) isTrue() bool { return true }
func (f FuncV0) Eval(_ *Env) Value { return f }
func (f FuncV0) String() string { return "<FunctionV1>" }
type FuncV1 func(Value) Value
func (f FuncV1) Argc() int { return 1 }
func (f FuncV1) isTrue() bool { return true }
func (f FuncV1) Eval(_ *Env) Value { return f }
func (f FuncV1) String() string { return "<FunctionV1>" }
type FuncV2 func(Value, Value) Value
func (f FuncV2) Argc() int { return 2 }
func (f FuncV2) isTrue() bool { return true }
func (f FuncV2) Eval(_ *Env) Value { return f }
func (f FuncV2) String() string { return "<FunctionV2>" }
// ユーザ定義関数
type FuncU struct {
name string
xs []Variable
body Expr
}
func newFuncU(name string, xs []Variable, body Expr) *FuncU {
return &FuncU{name, xs, body}
}
func (f *FuncU) Argc() int { return len(f.xs) }
func (f *FuncU) isTrue() bool { return true }
func (f *FuncU) Eval(_ *Env) Value { return f }
func (f *FuncU) String() string { return fmt.Sprintf("<%s>", f.name) }
// クロージャ
type Clo struct {
xs []Variable
body Expr
}
func newClo(xs []Variable, body Expr) *Clo {
return &Clo{xs, body}
}
type FuncC struct {
xs []Variable
body Expr
env *Env
}
func (f *FuncC) Argc() int { return len(f.xs) }
func (_ *FuncC) isTrue() bool { return true }
func (f *FuncC) Eval(_ *Env) Value { return f }
func (_ *FuncC) String() string { return "<Closure>" }
func (a *Clo) Eval(env *Env) Value {
return &FuncC{a.xs, a.body, env}
}
//
// 関数呼び出し
//
type App struct {
fn Func
xs []Expr
}
func newApp(fn Func, xs []Expr) *App {
return &App{fn, xs}
}
type AppV struct {
fn Expr
xs []Expr
}
func newAppV(fn Expr, xs []Expr) *AppV {
return &AppV{fn, xs}
}
func valueToFloat(v Value) float64 {
switch x := v.(type) {
case Int: return float64(x)
case Flt: return float64(x)
default:
panic(errorNum("", v))
}
}
// 評価
func appFunc(fn Func, xs []Expr, env *Env) Value {
switch f := fn.(type) {
case Func1:
x := valueToFloat(xs[0].Eval(env))
return Flt(f(x))
case Func2:
x := valueToFloat(xs[0].Eval(env))
y := valueToFloat(xs[1].Eval(env))
return Flt(f(x, y))
case FuncV0:
return f()
case FuncV1:
return f(xs[0].Eval(env))
case FuncV2:
return f(xs[0].Eval(env), xs[1].Eval(env))
case *FuncU:
return f.body.Eval(makeBinding(f.xs, xs, env))
case *FuncC:
return f.body.Eval(addBindingClo(f.xs, xs, env, f.env))
default:
panic(fmt.Errorf("%v is not function", f))
}
}
func (a *App) Eval(env *Env) Value {
return appFunc(a.fn, a.xs, env)
}
func (a *AppV) Eval(env *Env) Value {
v := a.fn.Eval(env)
fn, ok := v.(Func)
if !ok {
panic(fmt.Errorf("%v is not function", v))
}
if fn.Argc() != len(a.xs) {
panic(fmt.Errorf("wrong number of arguments"))
}
return appFunc(fn, a.xs, env)
}
//
// 組み込み関数の初期化
//
var funcTable = make(map[string]Func)
// 値の表示
func print(x Value) Value {
fmt.Print(sprintValue(x))
return x
}
func println(x Value) Value {
fmt.Println(sprintValue(x))
return x
}
// ベクタの生成
func makeVector(n, x Value) Value {
k := toInt(n)
xs := make(Vec, int(k))
for i := 0; i < int(k); i++ {
xs[i] = x
}
return xs
}
func length(v Value) Value {
xs, ok := v.(Vec)
if !ok {
panic(errorVec("len, ", v))
}
return Int(len(xs))
}
func isInt(v Value) Value {
_, ok := v.(Int)
return boolToValue(ok)
}
func isFlt(v Value) Value {
_, ok := v.(Flt)
return boolToValue(ok)
}
func isVec(v Value) Value {
_, ok := v.(Vec)
return boolToValue(ok)
}
func isStr(v Value) Value {
_, ok := v.(Str)
return boolToValue(ok)
}
func isFunc(v Value) Value {
_, ok := v.(Func)
return boolToValue(ok)
}
// 等値の判定
func eql(x, y Value) Value {
switch a := x.(type) {
case Func: return Int(0)
case Vec: return Int(0)
default: return boolToValue(a == y)
}
}
// リスト関連
func pair(v Value) Value {
_, ok := v.(*Cell)
return boolToValue(ok && v != NIL)
}
func null(v Value) Value {
return boolToValue(v == NIL)
}
func cons(x, y Value) Value {
return newCell(x, y)
}
func car(v Value) Value {
cp, ok := v.(*Cell)
if !ok {
panic(fmt.Errorf("car: List required, %v", v))
}
return cp.car
}
func cdr(v Value) Value {
cp, ok := v.(*Cell)
if !ok {
panic(fmt.Errorf("cdr: List required, %v", v))
}
return cp.cdr
}
func setCar(v, x Value) Value {
cp, ok := v.(*Cell)
if !ok {
panic(fmt.Errorf("setCar: List required, %v", v))
}
cp.car = x
return x
}
func setCdr(v, x Value) Value {
cp, ok := v.(*Cell)
if !ok {
panic(fmt.Errorf("setCdr: List required, %v", v))
}
cp.cdr = x
return x
}
// 時間
func clock() Value {
return Int(time.Now().UnixNano())
}
func since(v Value) Value {
x, ok := v.(Int)
if !ok {
panic(errorInt("since: ", v))
}
y := time.Now().UnixNano()
return Str(time.Duration(y - int64(x)).String())
}
// エラー
func userError(v Value) Value {
panic(fmt.Errorf("%v", v))
}
// 入力
func input(mes Value) Value {
var lex Lex
lex.Init(os.Stdin)
print(mes)
lex.getToken()
e := expression(&lex)
return e.Eval(nil)
}
func initFunc() {
funcTable["sqrt"] = Func1(math.Sqrt)
funcTable["sin"] = Func1(math.Sin)
funcTable["cos"] = Func1(math.Cos)
funcTable["tan"] = Func1(math.Tan)
funcTable["sinh"] = Func1(math.Sinh)
funcTable["cosh"] = Func1(math.Cosh)
funcTable["tanh"] = Func1(math.Tanh)
funcTable["asin"] = Func1(math.Asin)
funcTable["acos"] = Func1(math.Acos)
funcTable["atan"] = Func1(math.Atan)
funcTable["atan2"] = Func2(math.Atan2)
funcTable["exp"] = Func1(math.Exp)
funcTable["pow"] = Func2(math.Pow)
funcTable["log"] = Func1(math.Log)
funcTable["log10"] = Func1(math.Log10)
funcTable["log2"] = Func1(math.Log2)
funcTable["print"] = FuncV1(print)
funcTable["println"] = FuncV1(println)
funcTable["len"] = FuncV1(length)
funcTable["vector"] = FuncV2(makeVector)
funcTable["isInt"] = FuncV1(isInt)
funcTable["isFlt"] = FuncV1(isFlt)
funcTable["isStr"] = FuncV1(isStr)
funcTable["isVec"] = FuncV1(isVec)
funcTable["isFunc"] = FuncV1(isFunc)
funcTable["eql"] = FuncV2(eql)
funcTable["pair"] = FuncV1(pair)
funcTable["null"] = FuncV1(null)
funcTable["cons"] = FuncV2(cons)
funcTable["car"] = FuncV1(car)
funcTable["cdr"] = FuncV1(cdr)
funcTable["setCar"] = FuncV2(setCar)
funcTable["setCdr"] = FuncV2(setCdr)
funcTable["clock"] = FuncV0(clock)
funcTable["since"] = FuncV1(since)
funcTable["error"] = FuncV1(userError)
funcTable["input"] = FuncV1(input)
}
//
// 字句解析
//
type Lex struct {
scanner.Scanner
Token rune
}
func (lex *Lex) getToken() {
lex.Token = lex.Scan()
switch lex.Token {
case scanner.Ident:
key, ok := keyTable[lex.TokenText()]
if ok {
lex.Token = key
}
case '=':
if lex.Peek() == '=' {
lex.Next()
lex.Token = EQ
}
case '!':
if lex.Peek() == '=' {
lex.Next()
lex.Token = NE
} else {
lex.Token = NOT
}
case '<':
if lex.Peek() == '=' {
lex.Next()
lex.Token = LE
} else {
lex.Token = LT
}
case '>':
if lex.Peek() == '=' {
lex.Next()
lex.Token = GE
} else {
lex.Token = GT
}
}
}
//
// 構文解析
//
// 仮引数の取得
func getParameter(lex *Lex) []Variable {
e := make([]Variable, 0)
if lex.Token != '(' {
panic(fmt.Errorf("'(' expected"))
}
lex.getToken()
if lex.Token == ')' {
lex.getToken()
return e
}
for {
if lex.Token == scanner.Ident {
e = append(e, Variable(lex.TokenText()))
lex.getToken()
switch lex.Token {
case ')':
lex.getToken()
return e
case ',':
lex.getToken()
default:
panic(fmt.Errorf("unexpected token in parameter list"))
}
} else {
panic(fmt.Errorf("unexpected token in parameter list"))
}
}
}
// 引数の取得
func getArgs(lex *Lex) []Expr {
e := make([]Expr, 0)
if lex.Token != '(' {
panic(fmt.Errorf("'(' expected"))
}
lex.getToken()
if lex.Token == ')' {
lex.getToken()
return e
}
for {
e = append(e, expression(lex))
switch lex.Token {
case ')':
lex.getToken()
return e
case ',':
lex.getToken()
default:
panic(fmt.Errorf("unexpected token in argument list"))
}
}
}
// if 式の解析
func makeSel(lex *Lex) Expr {
testForm := expression(lex)
if lex.Token == THEN {
lex.getToken()
thenForm := expression(lex)
switch lex.Token {
case ELSE:
lex.getToken()
elseForm := expression(lex)
if lex.Token != END {
panic(fmt.Errorf("if, 'end' expected"))
}
lex.getToken()
return newSel(testForm, thenForm, elseForm)
case END:
lex.getToken()
return newSel(testForm, thenForm, Int(0))
default:
panic(fmt.Errorf("if, 'else' or 'end' expected"))
}
} else {
panic(fmt.Errorf("if, 'then' expected"))
}
}
// begin 式の解析
func getBody(lex *Lex) []Expr {
body := make([]Expr, 0)
for {
body = append(body, expression(lex))
switch lex.Token {
case ',':
lex.getToken()
default:
return body
}
}
}
func makeBegin(lex *Lex) Expr {
if lex.Token == END {
panic(fmt.Errorf("invalid begin form"))
}
body := getBody(lex)
if lex.Token != END {
panic(fmt.Errorf("'end' expected"))
}
lex.getToken()
return newBgn(body)
}
// while 式の解析
func makeWhile(lex *Lex) Expr {
testForm := expression(lex)
if lex.Token == DO {
lex.getToken()
return newWhl(testForm, makeBegin(lex))
} else {
panic(fmt.Errorf("'do' expected"))
}
}
// let 式の解析
func makeLet(lex *Lex) Expr {
vars := make([]Variable, 0)
vals := make([]Expr, 0)
for {
e := expression(lex)
a, ok := e.(*Agn)
if !ok {
panic(fmt.Errorf("let: invalid assign form"))
}
vars = append(vars, a.name)
vals = append(vals, a.expr)
if lex.Token == IN {
break
} else if lex.Token != ',' {
panic(fmt.Errorf("let, 'in' or ',' expected"))
}
lex.getToken()
}
lex.getToken()
return newLet(vars, vals, makeBegin(lex))
}
// 添字の取得
func getIndex(lex *Lex) []Expr {
xs := make([]Expr, 0)
lex.getToken()
for {
e := expression(lex)
if lex.Token != ']' {
panic(fmt.Errorf("']' expected"))
}
xs = append(xs, e)
lex.getToken()
if lex.Token != '[' {
return xs
}
lex.getToken()
}
}
// 因子
func factor(lex *Lex) Expr {
switch lex.Token {
case '(':
lex.getToken()
e := expression(lex)
if lex.Token != ')' {
panic(fmt.Errorf("')' expected"))
}
lex.getToken()
return e
case '[':
lex.getToken()
xs := getBody(lex)
if lex.Token != ']' {
panic(fmt.Errorf("']' expected"))
}
lex.getToken()
return newCrv(xs)
case '+':
lex.getToken()
return newOp1('+', factor(lex))
case '-':
lex.getToken()
return newOp1('-', factor(lex))
case NOT:
lex.getToken()
return newOp1(NOT, factor(lex))
case IF:
lex.getToken()
return makeSel(lex)
case BGN:
lex.getToken()
return makeBegin(lex)
case WHL:
lex.getToken()
return makeWhile(lex)
case LET:
lex.getToken()
return makeLet(lex)
case FN:
lex.getToken()
xs := getParameter(lex)
body := makeBegin(lex)
clo := newClo(xs, body)
if lex.Token == '(' {
ys := getArgs(lex)
if len(xs) != len(ys) {
panic(fmt.Errorf("wrong number of arguments: fn"))
}
return newAppV(clo, ys)
}
return clo
case LIST:
lex.getToken()
if lex.Token == '(' {
return newList(getArgs(lex))
}
panic(fmt.Errorf("List: '(' expected"))
case CALL:
lex.getToken()
xs := getArgs(lex)
if len(xs) == 0 {
panic(fmt.Errorf("wrong number of arguments: call"))
}
return newAppV(xs[0], xs[1:])
case scanner.Int:
var n int64
fmt.Sscan(lex.TokenText(), &n)
lex.getToken()
return Int(n)
case scanner.Float:
var n float64
fmt.Sscan(lex.TokenText(), &n)
lex.getToken()
return Flt(n)
case scanner.String:
var s string
fmt.Sscanf(lex.TokenText(), "%q", &s)
lex.getToken()
return Str(s)
case scanner.Ident:
name := lex.TokenText()
lex.getToken()
if name == "quit" {
panic(name)
}
v, ok := funcTable[name]
if ok {
if lex.Token == '(' {
xs := getArgs(lex)
if len(xs) != v.Argc() {
panic(fmt.Errorf("wrong number of arguments: %v", name))
}
return newApp(v, xs)
} else {
// 関数値をそのまま返す
return v
}
} else if lex.Token == '[' {
return newRef(Variable(name), getIndex(lex))
} else if lex.Token == '(' {
// 変数に格納されている関数を呼び出す
return newAppV(Variable(name), getArgs(lex))
} else {
return Variable(name)
}
default:
panic(fmt.Errorf("unexpected token: %v", lex.TokenText()))
}
}
// 項
func term(lex *Lex) Expr {
e := factor(lex)
for {
switch lex.Token {
case '*':
lex.getToken()
e = newOp2('*', e, factor(lex))
case '/':
lex.getToken()
e = newOp2('/', e, factor(lex))
case '%':
lex.getToken()
e = newOp2('%', e, factor(lex))
default:
return e
}
}
}
// 式
func expr3(lex *Lex) Expr {
e := term(lex)
for {
switch lex.Token {
case '+':
lex.getToken()
e = newOp2('+', e, term(lex))
case '-':
lex.getToken()
e = newOp2('-', e, term(lex))
default:
return e
}
}
}
// 比較演算子
func expr2(lex *Lex) Expr {
e := expr3(lex)
x := lex.Token
switch x {
case EQ, NE, LT, GT, LE, GE:
lex.getToken()
return newOp2(x, e, expr3(lex))
default:
return e
}
}
// 論理演算子
func expr1(lex *Lex) Expr {
e := expr2(lex)
for {
x := lex.Token
switch x {
case AND, OR:
lex.getToken()
e = newOps(x, e, expr2(lex))
default:
return e
}
}
}
func expression(lex *Lex) Expr {
e := expr1(lex)
if lex.Token == '=' {
switch x := e.(type) {
case Variable:
lex.getToken()
return newAgn(x, expression(lex))
case *Ref:
lex.getToken()
return newUdt(x, expression(lex))
default:
panic(fmt.Errorf("invalid assign form"))
}
}
return e
}
// ユーザ関数の定義
func defineFunc(lex *Lex) string {
lex.getToken()
if lex.Token != scanner.Ident {
panic(fmt.Errorf("invalid define form"))
}
name := lex.TokenText()
lex.getToken()
xs := getParameter(lex)
v, ok := funcTable[name]
if ok {
switch f := v.(type) {
case *FuncU:
if len(f.xs) != len(xs) {
panic(fmt.Errorf("wrong number of arguments: %v", name))
}
body := newBgn(getBody(lex))
if lex.Token != END {
panic(fmt.Errorf("'end' expected"))
}
f.xs = xs
f.body = body
default:
panic(fmt.Errorf("%v is built-in function", name))
}
} else {
// 再帰呼び出し対応
f := newFuncU(name, xs, nil)
funcTable[name] = f
f.body = newBgn(getBody(lex))
if lex.Token != END {
delete(funcTable, name)
panic(fmt.Errorf("'end' expected"))
}
}
return name
}
// ライブラリのロード
func loadLib(name string) {
var lex Lex
file, err := os.Open(name)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
defer func(){
err := recover()
file.Close()
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %v, %s\n", name, err, lex.Position)
os.Exit(1)
}
}()
lex.Init(file)
for {
lex.getToken()
if lex.Token == scanner.EOF {
break
} else if lex.Token == DEF {
defineFunc(&lex)
} else {
e := expression(&lex)
if lex.Token != ';' {
panic(fmt.Errorf("invalid expression"))
}
e.Eval(nil)
}
}
}
// 式の入力と評価
func toplevel(lex *Lex) (r bool) {
r = false
defer func(){
err := recover()
if err != nil {
mes, ok := err.(string)
if ok && mes == "quit" {
r = true
} else {
fmt.Fprintln(os.Stderr, err)
for {
c := lex.Peek()
if c == '\n' { break }
lex.Next()
}
}
}
}()
for {
fmt.Print("Calc> ")
lex.getToken()
if lex.Token == DEF {
fmt.Println(defineFunc(lex))
} else {
e := expression(lex)
if lex.Token != ';' {
panic(fmt.Errorf("invalid expression"))
} else {
println(e.Eval(nil))
}
}
}
return r
}
func main() {
initKeyTable()
initFunc()
makeNIL()
for _, name := range os.Args[1:] {
loadLib(name)
}
var lex Lex
lex.Init(os.Stdin)
for {
if toplevel(&lex) { break }
}
}