Hatena::Groupocaml-nagoya

yoshihiro503の関数的日記

2008-12-03 (Wed)

haXeでhaXe -> schemeジェネレーター

| 08:57 | haXeでhaXe -> schemeジェネレーター - yoshihiro503の関数的日記 を含むブックマーク はてなブックマーク - haXeでhaXe -> schemeジェネレーター - yoshihiro503の関数的日記

haXehaXeをパースしてscheme プログラムを生成しよう。

class Genscheme {

    public static function gen_class_field (class_field) {
	return switch class_field {
	    case fvar (name, expr):
		"(define "+name+" "+gen_expr(expr)+")";
	    case ffun (name, fun):
		"(define "+name+" "+gen_expr(efunction(fun))+")";
	    }
    }
    
    static function gen_expr (expr) {
	return switch expr {
	case econst(c): gen_const(c);
	case ecall(f, args):
            "("+gen_expr(f)+" "+List.string_concat (" ",List.map(gen_expr,args))+")";
	case efunction (f):
	    switch f {
	    case func(args, body):
	        "(lambda ("+List.string_concat (" ",args)+") "+gen_expr(body)+")";
	    }
	//case eswitch(e, cases): //TODO switch式
	//case evars (vs, e): //TODO let式
	case eexprs(e1, e2):
	    gen_expr(e1);
	case ereturn(e): gen_expr(e);
	default: "";
	}
    }


    static function gen_const (c) {
	return switch c {
	    case int(x): x;
	    case string(x): '"' + x + '"';
	    case ident(x): x;
	    case ctype(x): x;
	    }
    }
}

実行例

入力:

  static function main () {
    trace ("Hello, world!");
  }

出力:

(define main (lambda () (trace "Hello, world!")))

2008-12-02 (Tue)

haXeでhaXeコンパイラを作ってみる。

| 18:18 | haXeでhaXeコンパイラを作ってみる。 - yoshihiro503の関数的日記 を含むブックマーク はてなブックマーク - haXeでhaXeコンパイラを作ってみる。 - yoshihiro503の関数的日記

haXe全部の構文をサポートするのは大変そうなので、サブセット(MinHaXe?)を実装することにする。

具体的な構文は大体以下のBNFで定める。主要なものは全て入れたつもりだ。

   <ident> ::= [a-z] [a-zA-Z0-9_]*
   <constant> ::= <ident> | <string> | <number>

   <program> ::= <type_def> <type_def> .. <type_def>
   <type_def> ::= <class> | <enum>

   <class> ::= class <type_name> { <class_field list> }
   <class_field> ::= var <ident> = <expr> ;
                   | function <ident> ( <arg>, .. ,<arg> ) <expr>

   <enum> ::= enum { <enum_constructor list> }
   <enum_constructor> ::= <ident> ( <arg>, .. ,<arg> ) ;
                        | <ident> ;

   <expr> ::= { <block> }
            | ( <expr> )
	    | <constant> <expr_next>
	    | function ( <arg>, .. ,<arg> ) <expr>
	    | return <expr>
	    | switch <expr> { <case>, .. ,<case> }

   <expr_next> ::= . <expr_next>
                 | ( <expr>, .. , <expr> ) <expr_next>

   <block> ::= <expr> ; <block> | var <ident> = <expr> ; <block>

抽象構文木

抽象構文木は以下のように記述した。

enum Constant {
    int (s : String);
    string (s : String);
    ident (s : String);
    ctype (s : String);
}

enum TypeDef {
    eclass (name:String, fields : ListT<ClassField>);
    eenum (name:String, cs : ListT<EnumConstructor>);
}

enum ClassField {
    fvar (name:String, body : Expr);
    ffun (name:String, func : Func);
}

enum EnumConstructor {
    enum_const (cname : String, params : ListT<EnumParam>);
}
enum EnumParam {
    enum_param (vname : String, vtype : String);
}

enum Expr {
    econst (c : Constant);
    ecall (f : Expr, args : ListT<Expr>);
    efunction (f: Func);
    eswitch (e : Expr, cases : ListT<Pair<ListT<Expr>, Expr>>);
    evars (vs : ListT<Pair<String,Expr>>, e : Expr);// var vs; e
    eexprs(e1 : Expr, e2 : Expr);
    ereturn (e : Expr);
    efield (e :Expr, f : String);
    enil;
}
enum Func {
    func(arg_name: ListT<String>, body: Expr);
}

パーサー

まだ一部未完成だがこんな感じ。昨日のパーサーモナドをガンガン使っている。

class Parser {

    static function parse_class (source) {
	var parse_cf_rights = plist (ptoken(kwd(kstatic)));

	var parse_fun_args = psep(comma,mbind(pident,function(name) return
	     mbind(parse_type_opt, function (t) return mreturn(name))));
	var parse_fun_field = pignore_l (ptoken(kwd(kfunction)),
	     mbind (pident, function (fname) return
             pignore_l (ptoken(popen),
             mbind (parse_fun_args, function (args) return
             pignore_l (ptoken(pclose),
             mbind (parse_expr, function (body) return
             mreturn (ffun(fname, func(args,body)))))))));

	var parse_var_field = pignore_l (ptoken(kwd(kvar)),
             mbind(pident, function (vname) return
             mbind(parse_type_opt, function (t) return
             pignore_l(ptoken(binop(op_assign)),
	     mbind (parse_expr, function (expr) return
	     pignore_l (ptoken(semicolon), mreturn (fvar(vname, expr))))))));

	var parse_field = mbind (parse_cf_rights, function (as) return door (parse_var_field, parse_fun_field));
	var p = pignore_l (ptoken(kwd(kclass)),
	     mbind (ptype, function (name) return
	     pignore_l (ptoken(br_open),
	     mbind (plist(parse_field), function (fields) return
	     pignore_l (ptoken(br_close),
	     mreturn (eclass (name, fields)))))));	
	return p (source);
    }

    static function parse_expr (source) {
	// ブロック式のパーサ: { <block> }
	var p1 = pignore_l (ptoken(br_open), pignore_r (block, ptoken(br_close))); 
	// 丸カッコで囲まれた式のパーサ: ( <expr> )
	var p2 = pignore_l (ptoken(popen), pignore_r (parse_expr, ptoken(pclose)));
	// 定数、ident式のパーサ: <const> <expr_next>
	var p3 = mbind (pconst, Util.comp (expr_next, econst));
	// var p4 = //TODO: 無名関数のパーサ
	// return式のパーサ: return <expr>
	var p5 = pignore_l (ptoken(kwd(kreturn)), parse_expr);
	// var p6 = //TODO: switch式のパーサ
	return Util.apply (door(p1, door(p2, door(p3, p5))), source);
    }

    static function expr_next (e1) {
	// フィールド(メソッド)呼び出し: e1 . <expr_next>
	var p1 = pignore_l (ptoken(dot), mbind (pident, function (fld) return expr_next (efield(e1, fld))));
	// 関数適用: e1 ( <expr> , <expr> ,.., <expr> )	
	var p2 = pignore_l (ptoken(popen), pignore_r (mbind (psep(comma,parse_expr),
                      function (args) return expr_next (ecall(e1,args))), ptoken(pclose)));
							     
	return door (p1, door (p2, mreturn(e1)));
    }
    static function block (source) {
	// セミコロン区切りで並んだ式のパーサ: <expr>; <block>
	var p1 = mbind (parse_expr, function (e1) return pignore_l (ptoken(semicolon),
                     mbind (block, function (e2) return mreturn (eexprs(e1,e2)))));	
	//var p2 = //TODO var式のパーサ
	return Util.apply (door (p1, mreturn(enil)), source);
    }
}

syd_sydsyd_syd2008/12/02 23:31pignore_lとかpignore_rってなに?定義がないっぽいです。

yoshihiro503yoshihiro5032008/12/03 07:41ホントだ。失礼しました。
pignore_l(p1,p2)はパーサーp1で読んだ結果を無視してパーサーp2を適用するという関数で、pignore_rはその逆です。
static function pignore_l<S, X, Y> (p1 : ParserT<S, X>, p2 : ParserT<S, Y>) : ParserT<S, Y> {
return mbind (p1, function (_) return p2);
}
static function pignore_r<S, X, Y> (p1 : ParserT<S, X>, p2 : ParserT<S, Y>) : ParserT<S, X> {
return mbind (p1, function (x) return mbind (p2, function (_) return mreturn (x)));
}

syd_sydsyd_syd2008/12/04 01:50なるほど。 というか pなんとかのメソッド全て定義がないみたい。また教えてくださいな。

yoshihiro503yoshihiro5032008/12/05 14:00pなんとか関数などの小さい関数含めたソースコード全体をBitbacketに置きました。http://www.bitbucket.org/yoshihiro503/myhaxe/src/

wnvexszjfpwnvexszjfp2011/03/07 11:14ouw3YL <a href="http://ayeudredtsny.com/">ayeudredtsny</a>, [url=http://spyebfvidnog.com/]spyebfvidnog[/url], [link=http://kqgqdyzsdawf.com/]kqgqdyzsdawf[/link], http://pxxiblccbowy.com/