I am trying to parse some text following a grammer for Dynamic Epistemic Logic using Scala's RegexParser, as part of my Master Thesis. But I keep getting the same error on simple logical conjunctions. I understand where and why it's failing, but not why it's matching what it is in the first place.
My Code (severely boiled down to isolate the problem):
import scala.util.parsing.combinator._
class Formula() {
def and(q:Formula) = Conjunction(this, q) // ∧
}
abstract class Literal extends Formula
abstract class Constant extends Formula
case class Atom(symbol:String) extends Literal
case class NotAtom(p:Atom) extends Literal
case class Conjunction(p:Formula, q:Formula) extends Formula
class mapParser extends RegexParsers {
val conjOp = "&"
val negOp = "~"
val listseparator = ","
val leftparen = "("
val rightparen = ")"
def id:Parser[String] = "[a-z_]+".r // fluents are never capitalized. but may have underscore.
def litargs: Parser[String] = repsep("[a-zA-Z]+".r,listseparator) ^^ {case list => "(" + list.toString.stripPrefix("List") + ")"}
def atom: Parser[Atom] = id~leftparen~litargs~rightparen ^^ {case head~_~tail~_ => Atom(head+tail)}
def negAtom: Parser[NotAtom] = negOp~>atom ^^ (NotAtom(_))
def literal: Parser[Literal] = negAtom | atom
def and: Parser[Formula] = formula~conjOp~formula ^^ {case p1~_~p2 => Conjunction(p1,p2)}
def formula: Parser[Formula] = literal | and
};
object DomainParser extends mapParser {
def test() = {
val domainDesc ="present(A) & ~present(B)";
println("input: " + domainDesc)
println("result: " + apply(domainDesc))
}
def apply(domainDesc: String) = parseAll(formula, domainDesc) match {
case Success(result, _) => result
case failure : NoSuccess => scala.sys.error(failure.msg)
}
}
I am calling the DomainParser.test() function externally from java. The input is
present(A) & ~present(B)
which should yield:
Conjunction(Atom(present((A))),NotAtom(Atom(present((B)))))
but instead gives me the error:
Exception in thread "main" java.lang.RuntimeException: string matching regex `\z' expected but `&' found
at scala.sys.package$.error(package.scala:27)
at mAp.DomainParser$.apply(DEL.scala:48)
at mAp.DomainParser$.test(DEL.scala:43)
at mAp.DomainParser.test(DEL.scala)
at ma.MA.main(MA.java:8)
Furthermore, if I call the 'and' parser directly instead of the 'formula' parser, it works fine. Hence the problem seems to be with this line:
def formula: Parser[Formula] = literal | and
Because it attempts to parse the whole line as a single literal. It then parses present(A) correctly, but instead of failing on the '&' (not part of literal's parser) and returning to parse as an 'and'-term, it fails with the exception.
I cannot for the love of... see why it tries to match any '\z' at all. It is not included in the grammar by me, and even if it was - shouldn't it fail and try to parse as the next term instead of exiting with an exception? I am torn between thinking there is some in-built functionality for end-of-string terms that I do not know, to thinking there is something hugely obvious staring me in the face.
Any help would be sorely needed, very welcome and thank you very much in advance.
Dan True