1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
import scala.util.matching.Regex // Unambiguous grammar // E -> T + E | T // T -> Const | Var // Easier to parse grammar // S -> E$ // E -> Terminal E2 // E2 -> + E // E2 -> NIL // Terminal -> Const // Terminal -> Val abstract class S { def eval(env: Main.Environment): Int } abstract class Terminal extends S case class E(l: Terminal, right: Option[E2]) extends S { def eval(env: Main.Environment): Int = { val a1: Int = l match { case v:Var => v.eval(env) case c:Const => c.eval(env) } right match { case Some(r) => a1 + r.eval(env) case None => a1 } } } case class E2(l: E) extends S { def eval(env: Main.Environment): Int = l.eval(env) } case class Var(n: String) extends Terminal { def eval(env: Main.Environment): Int = env(n) } case class Const(v: Int) extends Terminal { def eval(env: Main.Environment): Int = v } class RecursiveDescent(input:String) { val constregex: Regex = "^[0-9]+".r val varregex: Regex = "^[A-Za-z]+".r var index = 0 def parseS(): S = parseE() def parseE(): E = E(parseTerminal(), parseE2()) def parseE2(): Option[E2] = { if (index < input.length && input(index) == '+'){ index+=1; // Advance past + Some(E2(parseE())) } else None } def parseTerminal(): Terminal = { // Get the unparsed part of the string. val currStr = input.substring(index) // Get either the const or var which is there. val consts = constregex.findAllIn(currStr) if (consts.hasNext){ val const: String = consts.next() index += const.length() Const(const.toInt) } else { val vars = varregex.findAllIn(currStr) val varname = vars.next() index += varname.length() Var(varname) } } } object Main { type Environment = String => Int def main(args: Array[String]){ val env: Environment = { case "x" => 5 case "y" => 7 } val rd = new RecursiveDescent("x+x+7+y") val exp2rd:S = rd.parseE() println(exp2rd) println(exp2rd.eval(env)) } } |