aio*_*obe 14 redundancy pretty-print
我的问题:在没有多余括号的情况下,打印表达式的最简洁方法是什么?
我有lambda表达式的以下表示:
Term ::= Fun(String x, Term t)
| App(Term t1, Term t2)
| Var(String x)
Run Code Online (Sandbox Code Playgroud)
按惯例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
}
Run Code Online (Sandbox Code Playgroud)
上面的打印机总是放置( )表达式(原子变量除外).因此Fun(x, App(Fun(y, x), y))它产生了
(? x.((? y.x) y))
Run Code Online (Sandbox Code Playgroud)
我想拥有
? x.(? y.x) y
Run Code Online (Sandbox Code Playgroud)
在这里,我将使用一个简单的语法来处理具有由以下语法定义的结合性和优先级的中缀表达式,其运算符按优先级升序列出
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
Run Code Online (Sandbox Code Playgroud)
给定一个抽象语法树(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;
}
}
Run Code Online (Sandbox Code Playgroud)
是不是只要检查App的参数类型就可以了?
\n\n我不知道如何用 scala 编写这个..
\n\nterm match {\n case Fun(v: String, t: Term) => "\xce\xbb %s.%s".format(v, prettyPrint(t))\n case App(s: Fun, t: App) => "(%s) (%s)".format(prettyPrint(s), prettyPrint(t))\n case App(s: Term, t: App) => "%s (%s)".format(prettyPrint(s), prettyPrint(t))\n case App(s: Fun, t: Term) => "(%s) %s".format(prettyPrint(s), prettyPrint(t))\n case App(s: Term, t: Term) => "%s %s".format(prettyPrint(s), prettyPrint(t))\n case Var(v: String) => v\n}\nRun Code Online (Sandbox Code Playgroud)\n