EBNF 到 Scala 解析器组合器
我有以下要解析的 EBNF:
PostfixExp -> PrimaryExp ( "[" Exp "]"
| . id "(" ExpList ")"
| . length )*
这就是我得到的:
def postfixExp: Parser[Expression] = (
primaryExp ~ rep(
"[" ~ expression ~ "]"
| "." ~ ident ~"(" ~ repsep(expression, "," ) ~ ")"
| "." ~ "length") ^^ {
case primary ~ list => list.foldLeft(primary)((prim,post) =>
post match {
case "[" ~ length ~ "]" => ElementExpression(prim, length.asInstanceOf[Expression])
case "." ~ function ~"(" ~ arguments ~ ")" => CallMethodExpression(prim, function.asInstanceOf[String], arguments.asInstanceOf[List[Expression]])
case _ => LengthExpression(prim)
}
)
})
但我想知道是否有更好的方法,最好不必诉诸强制转换(asInstanceOf)。
I have the following EBNF that I want to parse:
PostfixExp -> PrimaryExp ( "[" Exp "]"
| . id "(" ExpList ")"
| . length )*
And this is what I got:
def postfixExp: Parser[Expression] = (
primaryExp ~ rep(
"[" ~ expression ~ "]"
| "." ~ ident ~"(" ~ repsep(expression, "," ) ~ ")"
| "." ~ "length") ^^ {
case primary ~ list => list.foldLeft(primary)((prim,post) =>
post match {
case "[" ~ length ~ "]" => ElementExpression(prim, length.asInstanceOf[Expression])
case "." ~ function ~"(" ~ arguments ~ ")" => CallMethodExpression(prim, function.asInstanceOf[String], arguments.asInstanceOf[List[Expression]])
case _ => LengthExpression(prim)
}
)
})
But I would like to know if there is a better way, preferably without having to resort to casting (asInstanceOf).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我会这样做:
为了简洁起见,将
表达式
缩短为expr
,并出于同样的原因添加类型别名E
。我在这里使用的避免丑陋案例分析的技巧是从内部产生式返回一个函数值。 此函数采用一个
Expression
(这将是primary
),然后基于第一个表达式返回一个新的Expression
。 这统一了点调度和括号表达式的两种情况。 最后,collapse
方法用于将函数值的线性List
合并到适当的 AST,从指定的主表达式开始。请注意,
LengthExpression
只是从其各自的产生式中作为值返回(使用^^^
)。 这是有效的,因为案例类的伴随对象(假设 LengthExpression 确实是一个案例类)扩展了委托给其构造函数的相应函数值。 因此,LengthExpression
表示的函数采用单个Expression
并返回LengthExpression
的新实例,恰好满足了我们对高阶树的需求建造。I would do it like this:
Shortened
expressions
toexpr
for brevity as well as added the type aliasE
for the same reason.The trick that I'm using here to avoid the ugly case analysis is to return a function value from within the inner production. This function takes an
Expression
(which will be theprimary
) and then returns a newExpression
based on the first. This unifies the two cases of dot-dispatch and bracketed expressions. Finally, thecollapse
method is used to merge the linearList
of function values into a proper AST, starting with the specified primary expression.Note that
LengthExpression
is just returned as a value (using^^^
) from its respective production. This works because the companion objects for case classes (assuming thatLengthExpression
is indeed a case class) extend the corresponding function value delegating to their constructor. Thus, the function represented byLengthExpression
takes a singleExpression
and returns a new instance ofLengthExpression
, precisely satisfying our needs for the higher-order tree construction.