C2Eを変えてみる
パーサ追加して、簡単な評価器を付けてみましたよ。
これをどんどん拡張していけば、バックエンドはmincamlとかと同じ物を使ったり出来て楽しいのではないかと思います。
package C2E5 import util.parsing.combinator._ object parser extends RegexParsers { def expr: Parser[E] = term~rep("+"~>term) ^^ { case a ~ b => b.foldLeft[E](a){case (a, b)=> EAdd(a,b)} } def term : Parser[E] = factor~rep("*"~>factor) ^^ { case a ~ b => b.foldLeft[E](a){case(a, b) => EMul(a,b)} } def factor: Parser[E] = intLiteral | valExpr | id | "("~>expr<~")" | block | unit def unit: Parser[E] = ";" ^^ { a => EUnit } def block: Parser[E] = "{" ~> rep(expr) <~ "}" ^^ { a => def c2e(l:List[E]):E = { l match { case List() => EUnit case List(a) => a case ELet(a,b,EUnit)::c => ELet(a, b, c2e(c)) case a::b => ELet(null, a, c2e(b)) } } ELet(null,EUnit,c2e(a.filter{a=>a != EUnit})) } def valExpr : Parser[E] = ("val"~>id)~("="~>expr) ^^ { case(EId(a) ~ b) => ELet(a, b, EUnit) } def intLiteral : Parser[E] = """-?[1-9][0-9]*|0""".r ^^ { a => EInt(a.toInt) } def id : Parser[EId] = """[_a-zA-Z][_a-zA-Z0-9]*""".r ^^ { a => EId(a) } def parse(str:String) = { parseAll(expr, str) match { case Success(tree,_) => tree case e => throw new Exception(""+e) } } } sealed trait E case class EInt(a:Int) extends E case class EAdd(a:E,b:E) extends E case class EMul(a:E,b:E) extends E case class ELet(a:String, b:E, c:E) extends E case class EId(a:String) extends E object EUnit extends E object Main { def main(argv:Array[String]) { test(Map(),"1",EInt(1)) test(Map("a"->1),"a", EId("a")) test(Map(),"1+2", EAdd(EInt(1),EInt(2))) test(Map(),"val a = 1", ELet("a",EInt(1),EUnit)) test(Map(),"{}", ELet(null, EUnit, EUnit)) test(Map(),"{1}",ELet(null,EUnit,EInt(1))) test(Map("a"->1),"{a}", ELet(null,EUnit,EId("a"))) test(Map(),"{1+2}", ELet(null,EUnit,EAdd(EInt(1),EInt(2)))) test(Map(),"{val a = 1}", ELet(null,EUnit,ELet("a",EInt(1),EUnit))) test(Map(),"{{}}", ELet(null, EUnit,ELet(null, EUnit, EUnit))) test(Map(),"{1 1}",ELet(null, EUnit,ELet(null,EInt(1),EInt(1)))) test(Map(),"{1 2 3}",ELet(null, EUnit, ELet(null,EInt(1),ELet(null, EInt(2), EInt(3))))) test(Map(),"{val a = 1 a}", ELet(null,EUnit,ELet("a",EInt(1),EId("a")))) test(Map(),"{val a = 1 val b = 2}",ELet(null,EUnit, ELet("a",EInt(1),ELet("b",EInt(2),EUnit)))) test(Map(),"{{ val a = 1} val b = 2}",ELet(null,EUnit, ELet(null,ELet(null,EUnit, ELet("a",EInt(1),EUnit)),ELet("b",EInt(2),EUnit)))) test("{val a = 5 { val a = 1} val b = 2 a}", 5) } def test(env:Map[String,Int],s:String,e:E) { val e2 = parser.parse(s) if (e2 != e) throw new Exception("error "+s+" expected "+e+" but found "+e2) println(s+"="+eval(env,e2)) } def test(s:String,e:Int) { val e2 = parser.parse(s) val e3 = eval(Map(), e2) if (e3 != e) throw new Exception("error "+s+" expected "+e+" but found "+e3) println(s+"="+e3) } def eval(env:Map[String,Int], e:E):Int = e match { case EInt(a) => a case EAdd(a, b) => eval(env,a) + eval(env, b) case EMul(a, b) => eval(env,a) * eval(env, b) case ELet(a, b, c) => eval(env+(a->eval(env,b)),c) case EId(a) => env(a) case EUnit => 0 } }