Skip to content

Instantly share code, notes, and snippets.

Created November 13, 2008 10:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anonymous/24404 to your computer and use it in GitHub Desktop.
Save anonymous/24404 to your computer and use it in GitHub Desktop.
/*
* 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