expr ::= term (( "+" | "-" ) expr)? term ::= factor (( "*" | "/") term)? factor ::= wholeNumber | "(" expr ")"
expr term factor
wholeNumber
" ("
"+"
...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))))
^^
operator to transform. For example,
wholeNumber ^^ (_.toInt)
def expr: Parser[Int] = (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[Int] = wholeNumber ^^ (_.toInt) | "(" ~> expr <~ ")"
Parser[...]
type must match the return type of the transforms (here, Int
)Int
works if we interpret an arithmetic expression without variablesParser[Expr]
class Expr case class Number(value : Int) extends Expr case class Variable(name : String) extends Expr case class Operator(left : Expr, right : Expr, f: (Int, Int) => Int) extends Expr
class SimpleLanguageParser extends JavaTokenParsers { def expr: Parser[Expr] = (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 - 5
expr ::= 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[Expr] = term ~ rep(("+" | "-") ~ term) def term: Parser[Expr] = factor ~ rep(("*" | "/" ) ~ factor) def factor: Parser[Expr] = 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
a+b+c / \ a+b c / \ a b / \ 0 a
3 ~ List("-" ~ 4, "-" ~ 5)
-6 / \ -1 "-" ~ 5 / \ 3 "-" ~4
"-" ~ 4
case (x, "+" ~ y) => Operator(x, y, _ + _) case (x, "-" ~ y) => Operator(x, y, _ - _)
def expr: Parser[Expr] = (term ~ rep(("+" | "-") ~ term)) ^^ { case a ~ lst => (a /: lst) { case (x, "+" ~ y) => Operator(x, y, _ + _) case (x, "-" ~ y) => Operator(x, y, _ - _) }
Expr
with the correct structurelab9/report.txt
inside the Git repo. Include the coder's name in the report! Complete the program from slides 3 and 4.
import java.io._ import scala.util.parsing.combinator._ class SimpleLanguageParser1 extends JavaTokenParsers { def expr: Parser[Int] = (term ~ opt(("+" | "-") ~ expr)) ^^ { case a ~ None => a case a ~ Some("+" ~ b) => a + b case a ~ Some("-" ~ b) => a - b } . . . def factor: Parser[Int] = wholeNumber ^^ (_.toInt) | "(" ~> expr <~ ")" } object Main extends App { val parser = new SimpleLanguageParser1 val result = parser.parse(parser.expr, new InputStreamReader(System.in)) println(result) }
Complete the program from Slide 5.
import java.io._ import scala.util.parsing.combinator._ class Expr case class Number(value : Int) extends Expr case class Variable(name : String) extends Expr case class Operator(left : Expr, right : Expr, f: (Int, Int) => Int) extends Expr class SimpleLanguageParser2 extends JavaTokenParsers { def expr: Parser[Expr] = (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: Unfortunately, (Number(_.toInt))
doesn't work. Use (x => 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:
import java.io._ import scala.util.parsing.combinator._ class Expr ... class SimpleLanguageParser3 extends JavaTokenParsers { def expr: Parser[Expr] = (term ~ rep(("+" | "-") ~ term)) ^^ { case a ~ lst => (a /: lst) { case (x, "+" ~ y) => Operator(x, y, _ + _) case (x, "-" ~ y) => Operator(x, y, _ - _) } } ... } object Main extends App { ... }
3 - 4 - 5
? Variable
. How can you enhance your program to parse them as well, e.g. 3 - 4 * x
?