Created
November 7, 2011 19:23
-
-
Save kishida/1345875 to your computer and use it in GitHub Desktop.
Mini parser with parser combinators of scala.
This file contains 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
package miniparser | |
import scala.util.parsing.combinator.RegexParsers | |
object Main { | |
def main(args: Array[String]): Unit = { | |
val expr = """ | |
println("result: "+(3+(if ({ | |
println("cond"); | |
3 < 5 | |
}) println(12 * 2) else if(3+2) 15 + 3 else 0))); | |
12+6; | |
""" | |
val parser = new MiniParser | |
val ast = parser.parse(expr).get | |
val visitor = new ExprVisitor | |
var result = visitor.visit(ast); | |
println(result) | |
} | |
} | |
class ExprVisitor{ | |
def visit(ast:AST):Any = { | |
ast match{ | |
case Lines(exprs) =>{ | |
var result:Any = Unit | |
for(x <- exprs){ | |
result = visit(x) | |
} | |
result | |
} | |
case IfExpr(cond, pos, neg) =>{ | |
visit(cond) match{ | |
case true => visit(pos) | |
case false => visit(neg) | |
} | |
} | |
case LessOp(left, right) =>{ | |
(visit(left), visit(right)) match{ | |
case (lval:Int, rval:Int) => lval < rval | |
} | |
} | |
case AddOp(left, right) =>{ | |
(visit(left), visit(right)) match{ | |
case (lval:Int, rval:Int) => lval + rval | |
case (lval:String, rval) => lval + rval | |
case (lval, rval:String) => lval + rval | |
} | |
} | |
case SubOp(left, right) =>{ | |
(visit(left), visit(right)) match{ | |
case (lval:Int, rval:Int) => lval - rval | |
} | |
} | |
case MulOp(left, right) =>{ | |
(visit(left), visit(right)) match{ | |
case (lval:Int, rval:Int) => lval * rval | |
} | |
} | |
case IntVal(value) => value | |
case StringVal(value) => value | |
case PrintLine(value) => { | |
val v = visit(value); | |
println(v); | |
v | |
} | |
} | |
} | |
} | |
trait AST | |
case class Lines(exprs:List[AST]) extends AST | |
case class IfExpr(cond:AST, pos:AST, neg:AST) extends AST | |
case class LessOp(left: AST, right:AST) extends AST | |
case class AddOp(left: AST, right:AST) extends AST | |
case class SubOp(left: AST, right:AST) extends AST | |
case class MulOp(left: AST, right:AST) extends AST | |
case class StringVal(value: String) extends AST | |
case class PrintLine(value: AST) extends AST | |
case class IntVal(value: Int) extends AST | |
class MiniParser extends RegexParsers{ | |
//lines ::= expr {";" expr} [";"] | |
def lines: Parser[AST] = repsep(expr, ";")<~opt(";")^^{ | |
values => Lines(values) | |
} | |
//expr ::= cond | if | printLine | |
def expr: Parser[AST] = condOp|ifExpr|printLine | |
//if ::= "if" "(" expr ")" expr "else" expr | |
def ifExpr: Parser[AST] = "if"~"("~>expr~")"~expr~"else"~expr^^{ | |
case cond~_~pos~_~neg => IfExpr(cond, pos, neg) | |
} | |
//cond ::= add {"<" add} | |
def condOp: Parser[AST] = chainl1(add, | |
"<"^^{op => (left:AST, right:AST) => LessOp(left, right)}) | |
//add ::= term {"+" term | "-" term}. | |
def add: Parser[AST] = chainl1(term, | |
"+"^^{op => (left:AST, right:AST) => AddOp(left, right)}| | |
"-"^^{op => (left:AST, right:AST) => SubOp(left, right)}) | |
//term ::= factor {"*" factor} | |
def term : Parser[AST] = chainl1(factor, | |
"*"^^{op => (left:AST, right:AST) => MulOp(left, right)}) | |
//factor ::= intLiteral | stringLiteral | "(" expr ")" | "{" lines "}" | |
def factor: Parser[AST] = intLiteral | stringLiteral | | |
"("~>expr<~")"^^{ x=>x } | "{"~>lines<~"}"^^{x=>x} | |
//intLiteral ::= ["1"-"9"] {"0"-"9"} | |
def intLiteral : Parser[AST] = """[1-9][0-9]*|0""".r^^{ | |
value => IntVal(value.toInt)} | |
//stringLiteral ::= "\"" {"a-zA-Z0-9.."} "\"" | |
def stringLiteral : Parser[AST] = "\""~>"""[a-zA-Z0-9:*/+\- ]*""".r<~"\""^^{ | |
value => StringVal(value) | |
} | |
// printLine ::= "printLn" "(" expr ")" | |
def printLine: Parser[AST] = "println"~"("~>expr<~")"^^{ | |
value => PrintLine(value) | |
} | |
def parse(str:String) = parseAll(lines, str) | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment