问题
I'm doing Cay Horstmann's combinator parser exercises, I wonder about the best way to distinguish between strings that represent numbers and strings that represent variables in a match statement:
def factor: Parser[ExprTree] = (wholeNumber | "(" ~ expr ~ ")" | ident) ^^ {
case a: wholeNumber => Number(a.toInt)
case a: String => Variable(a)
}
The second line there, "case a: wholeNumber" is not legal. I thought about a regexp, but haven't found a way to get it to work with "case".
回答1:
I would split it up a bit and push the case analysis into the |
. This is one of the advantages of combinators and really LL(*) parsing in general:
def factor: Parser[ExprTree] = ( wholeNumber ^^ { Number(_.toInt) }
| "(" ~> expr <~ ")"
| ident ^^ { Variable(_) } )
I apologize if you're not familiar with the underscore syntax. Basically it just means "substitute the nth parameter to the enclosing function value". Thus { Variable(_) }
is equivalent to { x => Variable(x) }
.
Another bit of syntax magic here is the ~>
and <~
operators in place of ~
. These operators mean that the parsing of that term should include the syntax of both the parens, but the result should be solely determined by the result of expr
. Thus, the "(" ~> expr <~ ")"
matches exactly the same thing as "(" ~ expr ~ ")"
, but it doesn't require the extra case analysis to retrieve the inner result value from expr
.
来源:https://stackoverflow.com/questions/256694/scala-combinator-parsers-distinguish-between-number-strings-and-variable-strin