fprint 関数の自動生成

fprint 関数は (型 FILEref の) ファイルハンドルと値を取り、そのファイルハンドルにその値のテキスト表現を出力します。 あるデータ型が与えられたとき、そのデータ型の値を表わすテキスト表現を出力する関数がしばしば必要になります。 例えば、そのような関数はデバッグに威力を発揮します。

はじめに次のような関数テンプレート fprint_expr を宣言しましょう:

fun{} fprint_expr : (FILEref, expr) -> void // a function template

データ型 expr に対する fprint 関数の自動生成を (ATS コンパイラに) 指示する以下の命令を使うことができます:

#codegen2("fprint", expr, fprint_expr)

この場合、デフォルトと一致するので、codegen2 命令の第三引数は省略できます。 fprint_expr を実装する生成されたコードは次のようになります:

(* ****** ****** *) // extern fun{} fprint_expr$Int: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Var: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Add: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Sub: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Mul: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Div: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Ifgtz: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Ifgtez: $d2ctype(fprint_expr<>) // (* ****** ****** *) // implement{} fprint_expr (out, arg0) = ( case+ arg0 of | Int _ => fprint_expr$Int<>(out, arg0) | Var _ => fprint_expr$Var<>(out, arg0) | Add _ => fprint_expr$Add<>(out, arg0) | Sub _ => fprint_expr$Sub<>(out, arg0) | Mul _ => fprint_expr$Mul<>(out, arg0) | Div _ => fprint_expr$Div<>(out, arg0) | Ifgtz _ => fprint_expr$Ifgtz<>(out, arg0) | Ifgtez _ => fprint_expr$Ifgtez<>(out, arg0) ) // (* ****** ****** *) // extern fun{} fprint_expr$sep: (FILEref) -> void implement{} fprint_expr$sep(out) = fprint(out, ",") // extern fun{} fprint_expr$lpar: (FILEref) -> void implement{} fprint_expr$lpar(out) = fprint(out, "(") // extern fun{} fprint_expr$rpar: (FILEref) -> void implement{} fprint_expr$rpar(out) = fprint(out, ")") // extern fun{a:t0p} fprint_expr$carg: (FILEref, INV(a)) -> void implement{a} fprint_expr$carg(out, arg) = fprint_val<a>(out, arg) // (* ****** ****** *) // extern fun{} fprint_expr$Int$con: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Int$lpar: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Int$rpar: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Int$arg1: $d2ctype(fprint_expr<>) // implement{} fprint_expr$Int(out, arg0) = { // val () = fprint_expr$Int$con<>(out, arg0) val () = fprint_expr$Int$lpar<>(out, arg0) val () = fprint_expr$Int$arg1<>(out, arg0) val () = fprint_expr$Int$rpar<>(out, arg0) // } implement{} fprint_expr$Int$con(out, _) = fprint(out, "Int") implement{} fprint_expr$Int$lpar(out, _) = fprint_expr$lpar(out) implement{} fprint_expr$Int$rpar(out, _) = fprint_expr$rpar(out) implement{} fprint_expr$Int$arg1(out, arg0) = let val-Int(arg1) = arg0 in fprint_expr$carg(out, arg1) end // extern fun{} fprint_expr$Var$con: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Var$lpar: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Var$rpar: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Var$arg1: $d2ctype(fprint_expr<>) // implement{} fprint_expr$Var(out, arg0) = { // val () = fprint_expr$Var$con<>(out, arg0) val () = fprint_expr$Var$lpar<>(out, arg0) val () = fprint_expr$Var$arg1<>(out, arg0) val () = fprint_expr$Var$rpar<>(out, arg0) // } implement{} fprint_expr$Var$con(out, _) = fprint(out, "Var") implement{} fprint_expr$Var$lpar(out, _) = fprint_expr$lpar(out) implement{} fprint_expr$Var$rpar(out, _) = fprint_expr$rpar(out) implement{} fprint_expr$Var$arg1(out, arg0) = let val-Var(arg1) = arg0 in fprint_expr$carg(out, arg1) end // extern fun{} fprint_expr$Add$con: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Add$lpar: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Add$rpar: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Add$sep1: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Add$arg1: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Add$arg2: $d2ctype(fprint_expr<>) // implement{} fprint_expr$Add(out, arg0) = { // val () = fprint_expr$Add$con<>(out, arg0) val () = fprint_expr$Add$lpar<>(out, arg0) val () = fprint_expr$Add$arg1<>(out, arg0) val () = fprint_expr$Add$sep1<>(out, arg0) val () = fprint_expr$Add$arg2<>(out, arg0) val () = fprint_expr$Add$rpar<>(out, arg0) // } implement{} fprint_expr$Add$con(out, _) = fprint(out, "Add") implement{} fprint_expr$Add$lpar(out, _) = fprint_expr$lpar(out) implement{} fprint_expr$Add$rpar(out, _) = fprint_expr$rpar(out) implement{} fprint_expr$Add$sep1(out, _) = fprint_expr$sep<>(out) implement{} fprint_expr$Add$arg1(out, arg0) = let val-Add(arg1, _) = arg0 in fprint_expr$carg(out, arg1) end implement{} fprint_expr$Add$arg2(out, arg0) = let val-Add(_, arg2) = arg0 in fprint_expr$carg(out, arg2) end // extern fun{} fprint_expr$Sub$con: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Sub$lpar: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Sub$rpar: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Sub$sep1: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Sub$arg1: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Sub$arg2: $d2ctype(fprint_expr<>) // implement{} fprint_expr$Sub(out, arg0) = { // val () = fprint_expr$Sub$con<>(out, arg0) val () = fprint_expr$Sub$lpar<>(out, arg0) val () = fprint_expr$Sub$arg1<>(out, arg0) val () = fprint_expr$Sub$sep1<>(out, arg0) val () = fprint_expr$Sub$arg2<>(out, arg0) val () = fprint_expr$Sub$rpar<>(out, arg0) // } implement{} fprint_expr$Sub$con(out, _) = fprint(out, "Sub") implement{} fprint_expr$Sub$lpar(out, _) = fprint_expr$lpar(out) implement{} fprint_expr$Sub$rpar(out, _) = fprint_expr$rpar(out) implement{} fprint_expr$Sub$sep1(out, _) = fprint_expr$sep<>(out) implement{} fprint_expr$Sub$arg1(out, arg0) = let val-Sub(arg1, _) = arg0 in fprint_expr$carg(out, arg1) end implement{} fprint_expr$Sub$arg2(out, arg0) = let val-Sub(_, arg2) = arg0 in fprint_expr$carg(out, arg2) end // extern fun{} fprint_expr$Mul$con: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Mul$lpar: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Mul$rpar: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Mul$sep1: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Mul$arg1: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Mul$arg2: $d2ctype(fprint_expr<>) // implement{} fprint_expr$Mul(out, arg0) = { // val () = fprint_expr$Mul$con<>(out, arg0) val () = fprint_expr$Mul$lpar<>(out, arg0) val () = fprint_expr$Mul$arg1<>(out, arg0) val () = fprint_expr$Mul$sep1<>(out, arg0) val () = fprint_expr$Mul$arg2<>(out, arg0) val () = fprint_expr$Mul$rpar<>(out, arg0) // } implement{} fprint_expr$Mul$con(out, _) = fprint(out, "Mul") implement{} fprint_expr$Mul$lpar(out, _) = fprint_expr$lpar(out) implement{} fprint_expr$Mul$rpar(out, _) = fprint_expr$rpar(out) implement{} fprint_expr$Mul$sep1(out, _) = fprint_expr$sep<>(out) implement{} fprint_expr$Mul$arg1(out, arg0) = let val-Mul(arg1, _) = arg0 in fprint_expr$carg(out, arg1) end implement{} fprint_expr$Mul$arg2(out, arg0) = let val-Mul(_, arg2) = arg0 in fprint_expr$carg(out, arg2) end // extern fun{} fprint_expr$Div$con: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Div$lpar: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Div$rpar: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Div$sep1: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Div$arg1: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Div$arg2: $d2ctype(fprint_expr<>) // implement{} fprint_expr$Div(out, arg0) = { // val () = fprint_expr$Div$con<>(out, arg0) val () = fprint_expr$Div$lpar<>(out, arg0) val () = fprint_expr$Div$arg1<>(out, arg0) val () = fprint_expr$Div$sep1<>(out, arg0) val () = fprint_expr$Div$arg2<>(out, arg0) val () = fprint_expr$Div$rpar<>(out, arg0) // } implement{} fprint_expr$Div$con(out, _) = fprint(out, "Div") implement{} fprint_expr$Div$lpar(out, _) = fprint_expr$lpar(out) implement{} fprint_expr$Div$rpar(out, _) = fprint_expr$rpar(out) implement{} fprint_expr$Div$sep1(out, _) = fprint_expr$sep<>(out) implement{} fprint_expr$Div$arg1(out, arg0) = let val-Div(arg1, _) = arg0 in fprint_expr$carg(out, arg1) end implement{} fprint_expr$Div$arg2(out, arg0) = let val-Div(_, arg2) = arg0 in fprint_expr$carg(out, arg2) end // extern fun{} fprint_expr$Ifgtz$con: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Ifgtz$lpar: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Ifgtz$rpar: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Ifgtz$sep1: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Ifgtz$sep2: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Ifgtz$arg1: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Ifgtz$arg2: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Ifgtz$arg3: $d2ctype(fprint_expr<>) // implement{} fprint_expr$Ifgtz(out, arg0) = { // val () = fprint_expr$Ifgtz$con<>(out, arg0) val () = fprint_expr$Ifgtz$lpar<>(out, arg0) val () = fprint_expr$Ifgtz$arg1<>(out, arg0) val () = fprint_expr$Ifgtz$sep1<>(out, arg0) val () = fprint_expr$Ifgtz$arg2<>(out, arg0) val () = fprint_expr$Ifgtz$sep2<>(out, arg0) val () = fprint_expr$Ifgtz$arg3<>(out, arg0) val () = fprint_expr$Ifgtz$rpar<>(out, arg0) // } implement{} fprint_expr$Ifgtz$con(out, _) = fprint(out, "Ifgtz") implement{} fprint_expr$Ifgtz$lpar(out, _) = fprint_expr$lpar(out) implement{} fprint_expr$Ifgtz$rpar(out, _) = fprint_expr$rpar(out) implement{} fprint_expr$Ifgtz$sep1(out, _) = fprint_expr$sep<>(out) implement{} fprint_expr$Ifgtz$sep2(out, _) = fprint_expr$sep<>(out) implement{} fprint_expr$Ifgtz$arg1(out, arg0) = let val-Ifgtz(arg1, _, _) = arg0 in fprint_expr$carg(out, arg1) end implement{} fprint_expr$Ifgtz$arg2(out, arg0) = let val-Ifgtz(_, arg2, _) = arg0 in fprint_expr$carg(out, arg2) end implement{} fprint_expr$Ifgtz$arg3(out, arg0) = let val-Ifgtz(_, _, arg3) = arg0 in fprint_expr$carg(out, arg3) end // extern fun{} fprint_expr$Ifgtez$con: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Ifgtez$lpar: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Ifgtez$rpar: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Ifgtez$sep1: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Ifgtez$sep2: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Ifgtez$arg1: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Ifgtez$arg2: $d2ctype(fprint_expr<>) extern fun{} fprint_expr$Ifgtez$arg3: $d2ctype(fprint_expr<>) // implement{} fprint_expr$Ifgtez(out, arg0) = { // val () = fprint_expr$Ifgtez$con<>(out, arg0) val () = fprint_expr$Ifgtez$lpar<>(out, arg0) val () = fprint_expr$Ifgtez$arg1<>(out, arg0) val () = fprint_expr$Ifgtez$sep1<>(out, arg0) val () = fprint_expr$Ifgtez$arg2<>(out, arg0) val () = fprint_expr$Ifgtez$sep2<>(out, arg0) val () = fprint_expr$Ifgtez$arg3<>(out, arg0) val () = fprint_expr$Ifgtez$rpar<>(out, arg0) // } implement{} fprint_expr$Ifgtez$con(out, _) = fprint(out, "Ifgtez") implement{} fprint_expr$Ifgtez$lpar(out, _) = fprint_expr$lpar(out) implement{} fprint_expr$Ifgtez$rpar(out, _) = fprint_expr$rpar(out) implement{} fprint_expr$Ifgtez$sep1(out, _) = fprint_expr$sep<>(out) implement{} fprint_expr$Ifgtez$sep2(out, _) = fprint_expr$sep<>(out) implement{} fprint_expr$Ifgtez$arg1(out, arg0) = let val-Ifgtez(arg1, _, _) = arg0 in fprint_expr$carg(out, arg1) end implement{} fprint_expr$Ifgtez$arg2(out, arg0) = let val-Ifgtez(_, arg2, _) = arg0 in fprint_expr$carg(out, arg2) end implement{} fprint_expr$Ifgtez$arg3(out, arg0) = let val-Ifgtez(_, _, arg3) = arg0 in fprint_expr$carg(out, arg3) end // (* ****** ****** *)

fprint_expr に対するコードは全般的にテンプレートに基づいています。 このスタイルはテンプレートの再実装によってコードを柔軟にします。 データ型 expr は再帰的に定義されているので、fprint_expr を動作させるために次のテンプレート実装を追加する必要があります:

implement fprint_expr$card<expr> = fprint_expr

例えば、式 Add(Int(10),Mul(Int(1),Int(2)))fprint_expr を適用すると、同じテキスト表現が出力されます。 適応例として、次のテンプレート実装を追加してみましょう:

implement fprint_expr$Add$con<> (_, _) = () implement fprint_expr$Add$sep1<> (out, _) = fprint! (out, "+")

このとき式 Add(Int(10),Mul(Int(1),Int(2)))fprint_expr を適用すると、その出力は (Int(10)+Mul(Int(1),Int(2))) になるはずです。

適切な適応が行なわれたら、次のような (テンプレートではない) 関数を導入できます:

// extern fun my_fprint_expr(FILEref, expr): void implement my_fprint_expr (out, x) = fprint_expr<> (out, x) //

この方法で、my_fprint_expr を繰り返し呼び出したとしても、fprint_expr の唯一のインスタンスがコンパイルされます。

この章で示した例の全体と (コード生成のプロセスを説明する) Makefile は オンライン から入手できます。