I am trying to write an interpreter for the programming language Icon. One of the steps in this process is writing a parser for Icon, which I’ve done in the following way:
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)))
}
}
However, I’ve run into a few problems when I try to parse the following expression:
write((1 to 4) | 4)
I get this error:
java.lang.IllegalArgumentException: [9.17] failure: `)' expected but ` ' found
Whereas parsing
write((1 to 4) & 4)
works just fine. The first expression works fine if I move the orexp parser to an exp group above the fromto parser. However, this does not adhere to the rules given by Icon, and does not solve the underlying problem.
Does anyone have any ideas for solutions? According to the Scala docs, mixing packrat parsers and regular parsers should be ok.
Ok, I have read the paper on packrat parsers in Scala, and I’m afraid this grammar won’t work as is. The problem being that
fromToasexpinsidewrite, and thenwriteitself fails (and, having no other alternatives, the outerexpfails). It never goes back and say “well, let’s see if there’s anotherexpthat is also valid”.However, looking at this text, I don’t see
fromTohaving parenthesis as part of its grammar. If it were simply rewritten to remove those parenthesis from that level, it would work: