expr ::= term ( "+" | "-" ) expr
term ::= factor ( "*" | "/") term
factor ::= wholeNumber | "(" expr ")"
expr term factorwholeNumber "("
"+" ...
Not the same as an expression tree!
~, returns instance of class ~
(similar to a pair)|rep(P), returns List of the
results of Popt(P), returns Option:
Some of the result of P, or Noneclass SimpleLanguageParser extends JavaTokenParsers {
def expr: Parser[Any] = term ~ opt(("+" | "-") ~ expr)
def term: Parser[Any] = factor ~ opt(("*" | "/" ) ~ term)
def factor: Parser[Any] = wholeNumber | "(" ~ expr ~ ")"
}
((3~None)~Some((-~((4~Some((*~(5~None))))~None))))
Use ^^ operator to transform. For example,
wholeNumber ^^ (_.toDouble)
def expr: Parser[Double] = (term ~ opt(("+" | "-") ~ expr)) ^^ {
case a ~ None => a
case a ~ Some("+" ~ b) => a + b
case a ~ Some("-" ~ b) => a - b
}
~>, <~ to discard tokens
def factor: Parser[Double] = wholeNumber ^^ (_.toDouble) |
"(" ~> expr <~ ")"
Parser[...] type must match the return type of the
transforms (here, Double)Double works if we interpret an arithmetic
expression without variablesParser[ExprTree]
class ExprTree case class Number(value : Int) extends ExprTree case class Variable(name : String) extends ExprTree case class Operator(left : ExprTree, right : ExprTree, f: (Int, Int) => Int) extends ExprTree
class SimpleLanguageParser extends JavaTokenParsers {
def expr: Parser[ExprTree] = (term ~ opt(("+" | "-") ~ expr)) ^^ {
case a ~ None => a
case a ~ Some("+" ~ b) => Operator(a, b, _ + _)
case a ~ Some("-" ~ b) => Operator(a, b, _ - _)
}
...
}
Operator(Number(3),Operator(Number(4),Number(5),<function>),<function>)
3 - 4 - 5expr ::= term - expr
::= term - term - expr

expr and term?expr ::= expr - term ::= expr - expr - term :: expr - expr - expr - term
class SimpleLanguageParser extends JavaTokenParsers {
def expr: Parser[ExprTree] = term ~ rep(("+" | "-") ~ term)
def term: Parser[ExprTree] = factor ~ rep(("*" | "/" ) ~ factor)
def factor: Parser[ExprTree] = wholeNumber | "(" ~ expr ~ ")"
Operator(Operator(...(Operator(term1, term2, op1), term3, op2), ...)
foldLeft or the /:
operator
def sum(lst: List[Int]) = (0 /: lst) ((x, y) => x + y)
/: indicates the tree shape
+
/ \
+ c
/ \
+ b
/ \
0 a
3 ~ List("-" ~ 4, "-" ~ 5)
- / \ - 5 / \ 3 4
"-" ~ 4case (x, "+" ~ y) => Operator(x, y, _ + _) case (x, "-" ~ y) => Operator(x, y, _ - _)
def expr: Parser[ExprTree] = (term ~ rep(("+" | "-") ~ term)) ^^ {
case a ~ lst => (a /: lst) {
case (x, "+" ~ y) => Operator(x, y, _ + _)
case (x, "-" ~ y) => Operator(x, y, _ - _)
}
ExprTree with the correct
structure
Complete the program from slide 4.
package lab11.step1
import java.io._
import scala.util.parsing.combinator._
class SimpleLanguageParser extends JavaTokenParsers {
def expr: Parser[Double] = (term ~ opt(("+" | "-") ~ expr)) ^^ {
case a ~ None => a
case a ~ Some("+" ~ b) => a + b
case a ~ Some("-" ~ b) => a - b
}
. . .
def factor: Parser[Double] = wholeNumber ^^ (_.toDouble) | "(" ~> expr <~ ")"
}
object Main {
def main(args : Array[String]) : Unit = {}
val parser = new SimpleLanguageParser
val result = parser.parse(parser.expr, new InputStreamReader(System.in))
println(result)
}
Complete the program from Slide 5.
package lab11.step2
import java.io._
import scala.util.parsing.combinator._
class ExprTree
case class Number(value : Int) extends ExprTree
case class Variable(name : String) extends ExprTree
case class Operator(left : ExprTree, right : ExprTree,
f: (Int, Int) => Int) extends ExprTree
class SimpleLanguageParser extends JavaTokenParsers {
def expr: Parser[ExprTree] = (term ~ opt(("+" | "-") ~ expr)) ^^ {
case a ~ None => a
case a ~ Some("+" ~ b) => Operator(a, b, _ + _)
case a ~ Some("-" ~ b) => Operator(a, b, _ - _)
}
...
}
object Main {
def main(args : Array[String]) : Unit = {}
val parser = new SimpleLanguageParser
val result = parser.parse(parser.expr, new InputStreamReader(System.in))
println(result)
}
NOTE: For some reason, (Number(_.toInt)) didn't work out for
me, and I had to use { x : String => Number(x.toInt) }
expr and term in the
right hand side of the first production? Try parsing 3 - 4 - 5 again.Complete the program from slide 8:
package lab11.step3
import java.io._
import scala.util.parsing.combinator._
class ExprTree
case class Number(value : Int) extends ExprTree
case class Variable(name : String) extends ExprTree
case class Operator(left : ExprTree, right : ExprTree,
f: (Int, Int) => Int) extends ExprTree
class SimpleLanguageParser extends JavaTokenParsers {
def expr: Parser[ExprTree] = (term ~ rep(("+" | "-") ~ term)) ^^ {
case a ~ lst => (a /: lst) {
case (x, "+" ~ y) => Operator(x, y, _ + _)
case (x, "-" ~ y) => Operator(x, y, _ - _)
}
}
...
}
object Main {
def main(args : Array[String]) : Unit = {}
val parser = new SimpleLanguageParser
val result = parser.parse(parser.expr, new InputStreamReader(System.in))
println(result)
}
3 - 4 - 5? Variable. How can you enhance
your program to parse them as well, e.g. 3 - 4 * x?