定数畳み込みというか項書き換えシステムっぽい何か。
eクラスが式オブジェクトで、phpだと関数名とクラス名は同じもの使えるのでnewを書かなくてすむようにするためだけにe関数があります。
で、evalCompでコンパイル用の定数畳み込みっぽいことをする計算をしてグローバル変数の$chgという書き換えがあったかどうかフラグを
書き換えがあったら立てます。evalcでフラグを見てevalCompを繰り返し最大数分だけ呼び出します。
でif文を沢山書きたくないので型と演算子を文字列でくっつけて正規表現でマッチさせるというなんとも遅そうだけど短く書けるかもしれない手段を取ってみました。
対応している演算子は+と*だけで、しかも*はいまいちな対応です。
っていうことで、gccのソース*1
とかを見てみるけど、でかいので読む前に挫折。
うう、1万6千行とかある。。。うう。
mincamlの定数畳み込み*2は1+a+b+3は展開できないっぽい?
ということで、お、w_oさんの定数畳み込みがあった*3
ってことで、このソースは非常に恥ずかしいあまり意味のないものの気がしますが、まぁ、いいや。。。
<? class e { function __construct($l, $op, $r = null) { $this->l = $l; $this->op = $op; $this->r = $r; } } function e($l, $op = null, $r = null) { return new e($l, $op, $r); } $chg = false; function evalComp($e) { global $chg; switch ($e) { case $e instanceof e: $l = evalComp($e->l); $r = evalComp($e->r); $ls = is_integer($l)?"i":(is_string($l)?"s":"e"); $rs = is_integer($r)?"i":(is_string($r)?"s":"e"); $op2 = $ls.$e->op.$rs; echo $op2."\n"; $op3=""; switch (1) { case preg_match("/i[+]i/",$op2)>0: $chg = true; return $l+$r; case preg_match("/i[*]i/",$op2)>0: $chg = true; return $l*$r; case preg_match("/i[\\/]i/",$op2)>0: $chg = true; return $l/$r; case preg_match("/i[-]i/",$op2)>0: $chg = true; return $l-$r; case preg_match("/[is].e/",$op2)>0: $op3 = $ls . $e->op . (is_integer($r->l)?"i":(is_string($r->l)?"s":"e")) . $r->op . (is_integer($r->r)?"i":(is_string($r->r)?"s":"e")); echo $op3."\n"; switch(1){ case preg_match("/.[*].[+]./", $op3)>0: $chg=true; return e(e($l, "*", $r->l), "*", e($l, "*", $r->r)); } break; case preg_match("/e.[is]/",$op2)>0: $op3 = (is_integer($l->l)?"i":(is_string($l->l)?"s":"e")).$l->op. (is_integer($l->r)?"i":(is_string($l->r)?"s":"e")).$e->op.$rs; echo $op3."\n"; break; } switch(1){ case preg_match("/i[+].[+]i/", $op3)>0: $chg=true; return e($l + $r->r, "+", $r->l); case preg_match("/i[+]i[+]./", $op3)>0: $chg=true; return e($l + $r->l, "+", $r->r); case preg_match("/i[*].[*]i/", $op3)>0: $chg=true; return e($l * $r->r, "*", $r->l); case preg_match("/i[*]i[*]./", $op3)>0: $chg=true; return e($l * $r->l, "*", $r->r); case preg_match("/.[+]i[+]./", $op3)>0: $chg=true; return e($r->l, "+", e($l, "+", $r->r)); case preg_match("/.[*]i[*]./", $op3)>0: $chg=true; return e($r->l, "*", e($l, "*", $r->r)); case preg_match("/.[+].[+]i/", $op3)>0: $chg=true; return e($r->r, "+", e($l, "+", $r->l)); case preg_match("/.[*].[*]i/", $op3)>0: $chg=true; return e($r->r, "*", e($l, "*", $r->l)); } return e($l, $e->op, $r); default: return $e; } } function evalc($e) { global $chg; for($i=0;$i<100;$i++) { $chg = false; $e = evalComp($e); // if(!$chg) break; break; } return $e; } var_dump(evalc(e("a","+",e(2,"+",1)))); var_dump(evalc(e(1,"+",e(2,"+","a")))); var_dump(evalc(e(3,"+",e("b","+",e(2,"+","a"))))); var_dump(evalc(e("b","+",e(1,"+",e(5,"+","a"))))); var_dump(evalc(e(1,"+",e("a","+",e("b","+",e(5,"+","c"))))));