Parsecもどき

Haskellだとなんだかしらんけど、パーサコンビネータとかParsecとかがなんだか凄いらしい。
しかし、パーサコンビネータってどんなもんなん?
わからん。うー。
とりあえず、D言語で実装みたいなところまで来れたと。
いうわけで、


DによるParsecもどきです。
例外投げまくり、オブジェクト生成しまくり、なので、遅いです。
ある程度、最適化とか考えてみたんですが。いまいち。
D言語のデリゲードが関数抜けても使えたらもうちょっと、違う風に出来たと思うんですが、、、。

/*
   パーサコンビネータっぽいプログラム
 */
import std.string;

// キャッシュ的な仕組みの導入
template parser() {
	static Parser p; static Parser opCall() { return p; }
	static this() { p = new typeof(this)(); }
}
template parser(T) {
	static Parser[T] ps;
	static Parser opCall(T c) {
		if (c in ps) return ps[c];
		return ps[c] = new typeof(this)(c);
	}
	T f1;
	this(T f1) { this.f1 = f1; }
}
template parser(T,T2) {
	static Parser[T][T2] ps;
	static Parser opCall(T f1, T2 f2) {
		if (f2 in ps && f1 in ps[f2]) return ps[f2][f1];
		return ps[f2][f1] = new typeof(this)(f1, f2);
	}
	T f1; T2 f2;
	this(T f1, T2 f2) { this.f1 = f1; this.f2 = f2; }
}
template aliasParser() {
	static Parser p; static Parser opCall() { return p; }
}
//////////////////////////////////////////////////////////
class Tree {
	static Tree opCall() { return new Tree(); }
	static Tree opCall(char[] s, Tree[] ts ...) { return new Tree(s, ts); }
	char[] s;
	Tree[] ts;
	this(){}
	this(char[] s, Tree[] ts ...) {this.s = s;this.ts = ts.dup;}
	char[] toString() {
		char[] r;
		foreach (Tree t;ts)r ~= t.toString() ~ ",";
		if (r == "") return s;
		return s ~ "(" ~ r[0 .. r.length - 1] ~ ")";
	}
	Tree opUShr(Parser f) { return f.parse(this); } // >>> 演算子
	
	void print() {printf("%.*s\n", toString());}
}
//////////////////////////////////////////////////////////

class Parser {
	Tree parse(Tree t) { err(); return t;}
	Tree parse(char[] str) { return parse(Tree(str));}
	Parser opOr(Parser f)  { return OR(this, f); } 	// |  演算子
	Parser opShr(Parser f) { return AND(this, f); }	// >> 演算子
	void err()   { throw new Exception (toString()); }
	static void many(void delegate() d) {
		try {for (;;) {d();}} catch (Exception e) {}
	}
	static void or(void delegate() d1, void delegate() d2) {
		try { d1(); } catch (Exception e) { d2(); }
	}
}

class OR : Parser { mixin parser!(Parser,Parser);
	Tree parse(Tree t) {
		try{ return f1.parse(t); } catch (Exception e) { return f2.parse(t); }
	}
}

class AND : Parser { mixin parser!(Parser,Parser);
	Tree parse(Tree t) {
		Tree t2 = f2.parse(t = f1.parse(t));
		return Tree(t2.s, t.ts ~ t2.ts);
	}
}
//////////////////////////////////////////////////////////
class Just : Parser { mixin parser!();
	Tree parse(Tree t) { return Tree(t.s, Tree("")); }
}

class Char: Parser { mixin parser!(char);
	Tree parse(Tree t) {
		if (t.s[0] == f1) return Tree(t.s[1..length], Tree("" ~ f1));
		err();
	}
}

class ManyChars: Parser { mixin parser!(char[]);
	Tree parse(Tree t) {
		int i = 0;
		while (f1.find(t.s[i])!= -1) {i++;}
		if (i == 0) err();
		return Tree(t.s[i..length], Tree(t.s[0..i]));
	}
}

//////////////////////////////////////////////////////////
// alias 的なパーサ
class Number { mixin aliasParser!();
	static this() { p = ManyChars("0123456789"); }
}

class Space { mixin aliasParser!();
	static this() { p = ManyChars(" \t\r\n"); }
}

class SkipSpace { mixin aliasParser!();
	static this() { p = (Space() | Just()); }
}

//////////////////////////////////////////////////////////
class Exp: Parser { mixin parser!();
	Tree parse(Tree t) {
		t = t >>> Term();
		many({
			Tree t2 = t >>> (SkipSpace() >>(Char('+')|Char('-')) >> Term());
			t = Tree(t2.s, Tree(t2.ts[1].s, t.ts[0], t2.ts[2]));
		});
		return t;
	}
}

class Term: Parser { mixin parser!();
	Tree parse(Tree t) {
		t = t >>> Fact();
		many({
			Tree t2 = t >>> (SkipSpace() >> (Char('*')|Char('/')) >> Fact());
			t = Tree(t2.s, Tree(t2.ts[1].s, t.ts[0], t2.ts[2]));
		});
		return t;
	}
}

class Fact: Parser { mixin parser!();
	Tree parse(Tree t) {
		or({
			t = t >>> (SkipSpace() >> Number());
			t = Tree(t.s, t.ts[1]);
		},{
			t = t >>> (SkipSpace() >> Char('(') >> Exp() >> SkipSpace() >> Char(')'));
			t = Tree(t.s, t.ts[2]);
		});
		return t;
	}
}

//////////////////////////////////////////////////////////
import std.date;
void main() {
	int time = getUTCtime();
	for (int i = 0; i < 1000; i++) {
		Tree t = Exp().parse("  ( 123 + 2 ) - ( 4 - 5 ); ");
		t = Exp().parse(" 1 * 2 - 4 / 5;  ");
	}
	printf("%dms\n", getUTCtime() - time);
	Tree t = Exp().parse("  ( 123 + 2 ) - ( 4 - 5 ); ");
	t.print();
	t = Exp().parse(" 1 * 2 - 4 / 5;  ");
	t.print();
}