Created
November 13, 2008 10:28
-
-
Save anonymous/24404 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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" => 2 | |
case _ => -1 | |
} | |
val infixrs:(Any => Int) = { | |
case "=" => 5 | |
case _ => -1 | |
} | |
val prefixs:(Any => Int) = { | |
case "-" => 100 | |
case _ => -1 | |
} | |
val postfixs:(Any => Int) = { | |
case "++" => 100 | |
case ";" => 0 | |
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"),"(") => 1 | |
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)) | |
exp(p)(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(sts(x,p1))(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) && postfixs(op) == 0) => | |
val AS(y, ys) = exp(0)(AS(null, xs)) | |
if(y==null)AS((x,op),xs) | |
else exp(0)(AS(((x,op), "@", y), ys)) | |
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(null, xs) => as | |
case AS(x, xs) if (p <= 0) => | |
val AS(y, ys) = exp(0)(AS(null, xs)) | |
if(y != null) | |
exp(0)(AS((x, "@", y), ys)) | |
else | |
AS(x, xs) | |
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,"}") => 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 (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(eval(a, e) != 0) eval(b, e) else 0 | |
case a:Int => a | |
case a => throw new Error("runtime error " + a) | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment