我的问题:在没有多余括号的情况下打印表达式的最简洁方法是什么?
我有lambda表达式的以下表示:
Term ::= Fun(String x, Term t)
| App(Term t1, Term t2)
| Var(String x)
按惯例,App
是左关联的,即a b c
被解释为(a b) c
,函数体尽可能向右延伸,即λ x. x y
为解释为λ x. (x y)
。
我有一个做得很好的解析器,但现在我想要一个漂亮的打印机。这是我现在拥有的(伪scala):
term match {
case Fun(v, t) => "(λ %s.%s)".format(v, prettyPrint(t))
case App(s, t) => "(%s %s)".format(prettyPrint(s), prettyPrint(t))
case Var(v) => v
}
上述打印机始终将(
)
放在表达式周围(原子变量除外)。因此,Fun(x, App(Fun(y, x), y))
产生
(λ x.((λ y.x) y))
我想
λ x.(λ y.x) y
答案 0 :(得分:4)
这里我将使用一个简单的语法作为中缀表达式,其关联性和优先级由以下语法定义,其运算符按优先级的升序列出
E -> E + T | E - T | T left associative
T -> T * F | T / F | F left associative
F -> G ^ F | G right associative
G -> - G | ( E ) | NUM
给定抽象语法树(AST),我们将AST转换为只包含必要括号的字符串,如下面的伪代码所述。我们检查相对优先级和关联性,因为我们递归地下降树以确定何时需要括号。请注意,所有围绕表达式括起括号的决定必须在父节点中进行。
toParenString(AST) {
if (AST.type == NUM) // simple atomic type (no operator)
return toString(AST)
else if (AST.TYPE == UNARY_MINUS) // prefix unary operator
if (AST.arg.type != NUM AND
precedence(AST.op) > precedence(AST.arg.op))
return "-(" + toParenString(AST.arg) + ")"
else
return "-" + toParenString(AST.arg)
else { // binary operation
var useLeftParen =
AST.leftarg.type != NUM AND
(precedence(AST.op) > precedence(AST.leftarg.op) OR
(precedence(AST.op) == precedence(AST.leftarg.op) AND
isRightAssociative(AST.op)))
var useRightParen =
AST.rightarg.type != NUM AND
(precedence(AST.op) > precedence(AST.rightarg.op) OR
(precedence(AST.op) == precedence(AST.rightarg.op) AND
isLeftAssociative(AST.op)))
var leftString;
if (useLeftParen) {
leftString = "(" + toParenString(AST.leftarg) + ")"
else
leftString = toParenString(AST.leftarg)
var rightString;
if (useRightParen) {
rightString = "(" + toParenString(AST.rightarg) + ")"
else
rightString = toParenString(AST.rightarg)
return leftString + AST.op + rightString;
}
}
答案 1 :(得分:3)
是不是你只需要检查App的参数类型?
我不知道如何在scala中写这个...
term match {
case Fun(v: String, t: Term) => "λ %s.%s".format(v, prettyPrint(t))
case App(s: Fun, t: App) => "(%s) (%s)".format(prettyPrint(s), prettyPrint(t))
case App(s: Term, t: App) => "%s (%s)".format(prettyPrint(s), prettyPrint(t))
case App(s: Fun, t: Term) => "(%s) %s".format(prettyPrint(s), prettyPrint(t))
case App(s: Term, t: Term) => "%s %s".format(prettyPrint(s), prettyPrint(t))
case Var(v: String) => v
}