ftdop2.scala
次のscala東北勉強会で読む奴です。
いろいろ、未完成ですけど、このプログラムの発展形がC言語風言語で仕様が小さいながらパワフルな言語
のあるべき姿だと考えています。
C言語風の式言語がまずある。
で、その式言語を使う処理系はまた別個に用意されている。
そう、LISPとS式は別個で考えられるように。。。
/* * Copyright (c) 2008 h_sakurai, freecluster.net. All rights reserved. * * ftdop2.scala * Functional Top Down Operator Precedence * This program is Tiny programming language C Like eXpression Processor (TCLXP). * */ package ftdop2 import scala.util.matching.Regex import scala.collection.mutable.HashMap object main { def main(argv:Array[String]) { println(parse(argv(0))) println(eval(argv(0))) } // c like expression reader def parse(src:String) = { val symReg = """^[ \r\n\t]*([a-zA-Z_][a-zA-Z_0-9]*)(.*)""".r val numReg = """^[ \r\n\t]*([0-9]+)(.*)""".r val opReg = """^[ \r\n\t]*([+\-*/=]+|[a-zA-Z_][a-zA-Z_0-9]*)(.*)""".r val prnReg = """^[ \r\n\t]*([({\[])(.*)""".r val eoxReg = """^[ \r\n\t]*([)}\]].*|$)""".r val infixs:(Any => Int) = { case "*" => 20 case "/" => 20 case "-" => 10 case "+" => 10 case "else" => 100 case _ => -1 } val infixrs:(Any => Int) = { case "=" => 5 case _ => -1 } val prefixs:(Any => Int) = { case "-" => 1 case _ => -1 } val postfixs:(Any => Int) = { case "++" => 1 case _ => -1 } val parens:(Any => Int) = { case "(" => 100 case "{" => 100 case "[" => 100 case _ => -1 } val endParens:(Any => Regex) = { case "(" => """^[ \r\n\t]*(\))(.*)""".r case "{" => """^[ \r\n\t]*(\})(.*)""".r case "[" => """^[ \r\n\t]*(\])(.*)""".r } val sts:( (Any,String) => Int ) = { case (Symbol("if"),"(") => 100 case _ => -1 } sealed case class AS(a:Any, s:String) def eat(t:Regex)(as:AS):AS = t.unapplySeq(as.s) match { case Some(List(s,s2)) => AS(s, s2) case _ => throw new Error("error") } def exp(p:Int)(as:AS):AS = { //println("exp("+p+")("+as+")"); as match { case AS(null, numReg( x, xs)) => exp(p)(AS(x.toInt, xs)) case AS(null, symReg( x, xs)) => exp(p)(AS(Symbol(x), xs)) case AS(null, prnReg(p1, xs)) if (p < parens(p1)) => val AS(y, ys) = exp(0)(AS(null, xs)) val AS(p2, zs) = eat(endParens(p1))(AS(null, ys)) exp(p)(AS((p1,y,p2),zs)) case AS(null, opReg(op, xs)) if (p < prefixs(op)) => val AS(y, ys) = exp(prefixs(op))(AS(null, xs)) AS((op,y),ys) case AS(x, prnReg(p1, xs)) if (0 < sts(x,p1)) => val AS(y, ys) = exp(0)(AS(null, xs)) val AS(p2, zs) = eat(endParens(p1))(AS(null, ys)) val AS(w, ws) = exp(0)(AS(null, zs)) exp(p)(AS((x,p1,y,p2,w), ws)) case AS(x, prnReg(p1, xs)) if (sts(x,p1) < 0 && p < parens(p1)) => val AS(y, ys) = exp(0)(AS(null, xs)) val AS(p2, zs) = eat(endParens(p1))(AS(null, ys)) exp(p)(AS((x,p1,y,p2), zs)) case AS(x, opReg(op, xs)) if (p <= postfixs(op)) => AS((x,op),xs) case AS(x, opReg(op, xs)) if (p < infixs(op)) => val AS(y, ys) = exp(infixs(op))(AS(null, xs)) exp(p)(AS((x, op, y), ys)) case AS(x, opReg(op, xs)) if (p <=infixrs(op))=> val AS(y, ys) = exp(infixrs(op))(AS(null, xs)) exp(p)(AS((x, op, y), ys)) case AS(_, eoxReg(_)) => as case AS(x, xs) if (p <= 0) => val AS(y, ys) = exp(0)(AS(null, xs)) exp(0)(AS((x, "@", y), ys)) case as => as } } exp(0)(AS(null, src)).a } def eval(s:String):Int = eval(parse(s),new HashMap[String, Int]) // c like expression evaluator def eval(a:Any, e:HashMap[String,Int]):Int = a match { case Symbol(a) => e(a) case (Symbol(a),"=",b) => val r = eval(b,e); e += a -> r; r case (Symbol(a),"++") => val r = e(a); e += a -> (r + 1); r case (a,"@", b) => eval(a, e); eval(b, e) case ('print,"(", a,")") => val r = eval(a, e); println(r);r case (a,"(",b,")") => eval(a, e) + eval(b, e) case (a,"{",b,"}") => eval(a, e) * eval(b, e) case (a,"[",b,"]") => eval(a, e) - eval(b, e) case ("(",a,")") => eval(a, e) case (a,"+",b) => eval(a, e) + eval(b, e) case (a,"*",b) => eval(a, e) * eval(b, e) case (a,"-",b) => eval(a, e) - eval(b, e) case (a,"/",b) => eval(a, e) / eval(b, e) case ("-",a) => -eval(a, e) case ('if,"(",a,")",(b,"else",c)) => if(a != 0) eval(b, e) else eval(c, e) case ('if,"(",a,")", b) => if(a != 0) eval(b, e) else 0 case a:Int => a case a => throw new Error("runtime error " + a) } }