前回はクロージャを使って「連結リスト」を実装しました。今回は電卓プログラムに新しいデータ型として「連結リスト」を追加してみましょう。
最初に連結リストを表すデータ型を定義します。次のリストを見てください。
リスト : 連結リストの定義 // セル 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 } } }