Operator associativity using Scala Parsers

前端 未结 2 712
攒了一身酷
攒了一身酷 2021-01-16 08:07

So I\'ve been trying to write a calculator with Scala\'s parser, and it\'s been fun, except that I found that operator associativity is backwards, and that when I try to mak

2条回答
  •  佛祖请我去吃肉
    2021-01-16 08:27

    Scala's standard implementation of parser combinators (the Parsers trait) do not support left-recursive grammars. You can, however, use PackratParsers if you need left recursion. That said, if your grammar is a simple arithmetic expression parser, you most definitely do not need left recursion.

    Edit

    There are ways to use right recursion and still keep left associativity, and if you are keen on that, just look up arithmetic expressions and recursive descent parsers. And, of course, as, I said, you can use PackratParsers, which allow left recursion.

    But the easiest way to handle associativity without using PackratParsers is to avoid using recursion. Just use one of the repetition operators to get a List, and then foldLeft or foldRight as required. Simple example:

    trait Tree
    case class Node(op: String, left: Tree, right: Tree) extends Tree
    case class Leaf(value: Int) extends Tree
    
    import scala.util.parsing.combinator.RegexParsers
    
    object P extends RegexParsers {
      def expr = term ~ (("+" | "-") ~ term).* ^^ mkTree
      def term = "\\d+".r ^^ (_.toInt)
      def mkTree(input: Int ~ List[String ~ Int]): Tree = input match {
        case first ~ rest => ((Leaf(first): Tree) /: rest)(combine)
      }
      def combine(acc: Tree, next: String ~ Int) = next match {
        case op ~ y => Node(op, acc, Leaf(y))
      }
    }
    

    You can find other, more complete, examples on the scala-dist repository.

提交回复
热议问题