Как построить дерево синтаксического анализа простых выражений

#scala #parsing

#scala #синтаксический анализ

Вопрос:

Давайте построим дерево синтаксического анализа для простых выражений, таких как 3 - 4 * 5 , используя scala.util.parsing.combinator._ :

 def expr: Parser[Any] = term ~ opt((" "|"-") ~ expr)
def term: Parser[Any] = factor ~ opt(("*"|"/") ~ factor)
def factor: Parser[Any] = wholeNumber | "(" ~> expr <~ ")"
  

С 3 - 4 * 5 результирующее дерево имеет вид:

        expr
      / |  
  term  -   expr
   |       / |  
 factor term * term  
   |      |      |
 number factor factor
   |      |      |
   3    number number
          |      |
          4      5
  

что правильно. Но с 3 - 4 5 моим деревом, похоже, не исправляется:

        expr
      / |  
  term  -   expr
   |       / |  
 factor term   term  
   |      |      |
 number factor factor
   |      |      |
   3    number number
          |      |
          4      5
  

Как я могу это исправить? Я думал, что это решение:

def expr: Parser[Any] = expr ~ opt((" "|"-") ~ term)

но это слишком неправильно…

Мой полный код:

 import scala.util.parsing.combinator._


class Expr

case class Number(value: Int) extends Expr {
    override def toString = s"$value"
}

case class Operator(left: Expr, right: Expr, f: (Int, Int) => Int) extends Expr {
    override def toString = s"($f, $left, $right)"
}

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, _ - _)
    }

    def term: Parser[Expr] = (factor ~ opt(("*" | "/" ) ~ term)) ^^ {
        case a ~ None => a
        case a ~ Some("*" ~ b) => Operator(a, b, _ * _)
        case a ~ Some("/" ~ b) => Operator(a, b, _ / _)
    }

    def factor: Parser[Expr] = wholeNumber ^^ (n => Number(Integer.parseInt(n))) | "(" ~> expr <~ ")"

}

object Main {
    def main(args: Array[String]) = {
        val parser = new SimpleLanguageParser
        val result = parser.parse(parser.expr, "3 - 4   5")
        println(result)
    }
}
  

Комментарии:

1. Я новичок в библиотеке Scala parser combinator, поэтому, возможно, не смогу ответить на ваш вопрос: (но просто из любопытства, каков ваш ожидаемый результат?

2. предполагается, что это ((3 — 4) 5), мой (3 (4 — 5))

Ответ №1:

Я думаю, term ~ opt((" "|"-") ~ expr) не удалось сохранить порядок операций / -.

 def largerExpr: Parser[Any] = expr ~ opt((" "|"-") ~ expr)
def expr: Parser[Any] = term ~ opt((" "|"-") ~ term)
  

EIDT

 def expr1: Parser[Expr] = (expr ~ opt((" " | "-") ~ expr)) ^^ {
    case a ~ None => a
    case a ~ Some(" " ~ b) => Operator(a, b, _   _)
    case a ~ Some("-" ~ b) => Operator(a, b, _ - _)
}

def expr: Parser[Expr] = (term ~ opt((" " | "-") ~ term)) ^^ {
    case a ~ None => a
    case a ~ Some(" " ~ b) => Operator(a, b, _   _)
    case a ~ Some("-" ~ b) => Operator(a, b, _ - _)
}
  

Ваш результат был бы (<function2>, 3, (<function2>, 4, 5)) , результатом использования expr1 является (<function2>, (<function2>, 3, 4), 5)

Комментарии:

1. ваше решение анализирует только (3-4) и пропускает ( 5). Я добавил свой полный скрипт выше на всякий случай, если вам интересно…

2. @HuyVo сделал это? Я протестировал это перед отправкой ответа. Я все равно попробую с вашим кодом.

3. Спасибо, это была моя ошибка (я забыл изменить в val result = parser.parse(parser.expr, "3 - 4 5") ). Это работает идеально: D

4. @HuyVo Это был хороший шанс попробовать комбинатор синтаксического анализа Scala! 🙂