Scala парсер комбинаторы, парсеры не работают из-за приоритета - PullRequest
4 голосов
/ 17 июня 2011

Я пытаюсь написать переводчик для языка программирования Icon.Одним из шагов в этом процессе является написание синтаксического анализатора для Icon, который я сделал следующим образом:

import java.io.FileReader
import scala.util.parsing.combinator.syntactical._
import scala.util.parsing.combinator.RegexParsers
import scala.util.parsing.combinator.PackratParsers
import scala.util.parsing.combinator.JavaTokenParsers

abstract class expr
case class CstInt(val value : Int) extends expr
case class FromTo(val from : expr, val to : expr) extends expr
case class Write(val value : expr) extends expr
case class And(val e1 : expr, val e2 : expr) extends expr
case class Or(val e1 : expr, val e2 : expr) extends expr

object ExprParser extends JavaTokenParsers with PackratParsers{

lazy val exp : PackratParser[expr] = andexp | exp2

lazy val exp2 : PackratParser[expr] = fromTo | exp3

lazy val exp3 :PackratParser[expr] = orexp | exp4 

lazy val exp4 : PackratParser[expr] = integer | exp5

lazy val exp5 : PackratParser[expr] = write 

lazy val integer : PackratParser[expr] = wholeNumber ^^ { s => CstInt(s.toInt)}

lazy val  write : PackratParser[Write] =  "write" ~> "(" ~> exp <~ ")" ^^ {  e => Write(e)}

lazy val fromTo : PackratParser[FromTo] = ("(" ~> integer) ~ ("to" ~> integer <~ ")") ^^ { case from ~ to => FromTo(from, to)}

lazy val andexp : PackratParser[And] = exp ~ ("&" ~> exp) ^^ { case e1 ~ e2 => And(e1, e2)}

lazy val orexp : PackratParser[Or] = exp ~ ("|" ~> exp) ^^ { case e1 ~ e2 => Or(e1, e2)}

def parseInput(input: String) : expr =
    parseAll (exp, input) match {
        case Success(tree, _) => tree
        case e: NoSuccess => throw new IllegalArgumentException(e.toString())
    }

}

object Interpret {
def main(args : Array[String]) : Unit = {
    println(ExprParser.parseInput(args(0)))
    }
}

Однако я столкнулся с несколькими проблемами при попытке разобрать следующеевыражение:

write((1 to 4) | 4)

Я получаю эту ошибку:

java.lang.IllegalArgumentException: [9.17] failure: `)' expected but ` ' found

В то время как синтаксический анализ

write((1 to 4) & 4)

работает просто отлично.Первое выражение работает нормально, если я переместил анализатор orexp в группу exp над синтаксическим анализатором fromto.Однако это не соответствует правилам, данным Icon, и не решает основную проблему.

У кого-нибудь есть идеи для решений?В соответствии с документами Scala, смешанные парсеры packrat и обычные парсеры должны быть в порядке.

Ответы [ 2 ]

2 голосов
/ 17 июня 2011

Хорошо, я прочитал статью о пакетных парсерах в Scala, и я боюсь, что эта грамматика не будет работать как есть. Проблема в том, что fromTo как exp внутри write, а затем write само по себе отказывает (и, не имея других альтернатив, внешний exp отказывает). Он никогда не возвращается назад и не говорит «хорошо, давайте посмотрим, есть ли еще один exp, который также действителен» .

Однако, глядя на этот текст , я не вижу fromTo с круглыми скобками как частью его грамматики. Если бы он был просто переписан для удаления этих скобок с этого уровня, он бы работал:

object ExprParser extends JavaTokenParsers with PackratParsers{
  lazy val exp : PackratParser[expr] = andexp | exp2
  lazy val exp2 : PackratParser[expr] = fromTo | exp3
  lazy val exp3 :PackratParser[expr] = orexp | exp4 
  lazy val exp4 : PackratParser[expr] = integer | exp5
  lazy val exp5 : PackratParser[expr] = write | exp6
  lazy val exp6 : PackratParser[expr] = "(" ~> exp <~ ")"
  lazy val integer : PackratParser[expr] = wholeNumber ^^ { s => CstInt(s.toInt)}
  lazy val  write : PackratParser[Write] =  "write" ~> "(" ~> exp <~ ")" ^^ {  e => Write(e)}
  lazy val fromTo : PackratParser[FromTo] = integer ~ ("to" ~> integer) ^^ { case from ~ to => FromTo(from, to)}
  lazy val andexp : PackratParser[And] = exp ~ ("&" ~> exp) ^^ { case e1 ~ e2 => And(e1, e2)}
  lazy val orexp : PackratParser[Or] = exp3 ~ ("|" ~> exp) ^^ { case e1 ~ e2 => Or(e1, e2)}
}
0 голосов
/ 18 июня 2011

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

lazy val exp : PackratParser[expr] = (andexp | orexp | fromTo | integer | write)

А потом я изменил ваш порядок - fromTo былперечисленные ранее.

Кажется, теперь работает нормально.

Andrés

...