Reputation: 6571
I'm parsing a language with a parser-combinator in Scala, and I'd like to express the CFG rule
stmt -> if (stmt) {stmt}
Naturally, I wish to discard the "if(){}" string literals when constructing my result. The two ways I've considered are ugly.
Method (A) requires us to duplicate the position of the string literals inside the "case" statement:
lazy val stmt: PackratParser[Stmt] =
(
// other rules...
| "if"~"("~stmt~")"~"{"~stmt~"}" ^^ { case _~_~s1~_~_~s2~_ ⇒ If(s1, s2) }
)
Method (B) requires confusing parenthesis due to the precedence of ~ and ~>.
lazy val stmt: PackratParser[Stmt] =
(
// other rules...
| ("if"~>"("~>stmt)~(")"~>"{"~>stmt<~"}") ^^ { case s1~s2 ⇒ If(s1, s2) }
)
Ideally I'd like to discard the "(",")" literals without needing parenthesis in my Scala code. Is there a clean way to do this?
Upvotes: 3
Views: 137
Reputation: 139038
The usual way to avoid precedence issues without lots of parentheses is to define some helpers, and that works here pretty nicely, to my eye:
val cond = "(" ~> stmt <~ ")"
val thenClause = "{" ~> stmt <~ "}"
val ifStmt = "if" ~> cond ~ thenClause ^^ { case s1 ~ s2 => If(s1, s2) }
If this wasn't an option for some reason, I'd definitely avoid your first approach, and I'd adjust the second to make the precedence-managing parentheses match up more cleanly with the syntax—i.e., something like this:
"if" ~> ("(" ~> stmt <~ ")") ~ ("{" ~> stmt <~ "}") ^^ {
case s1 ~ s2 => If(s1, s2)
}
This isn't great, but it's not absolutely unreadable, either.
Upvotes: 4