2011-06-08 20 views
14

我的問題:什麼是最乾淨的方式來漂亮打印一個沒有多餘括號的表達式?漂亮的打印表達式儘可能少括號?


我有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)

我有一個分析器,它做了很好的工作,但現在我希望有一個漂亮的打印。這是我現在有(僞階):

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 
+4

我知道的唯一參考是Norman Ramsey的「用前綴和後置運算符解析表達式」。如果你知道一點標準ML,你應該可以修改第4部分的代碼。 http://www.cs.tufts.edu/~nr/pubs/unparse-abstract.html – 2011-06-24 13:05:50

+0

這種語言是不可知的,或者你正在尋找一個Scala答案?無論哪種方式,您可能想要標記問題以獲得更廣泛的受衆羣體。 – neontapir 2012-08-16 22:25:30

回答

2

不是吧,你只需要檢查的各類應用程序的參數呢?

我不知道如何在斯卡拉寫這個..

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 
} 
3

在這裏,我將使用一個簡單的語法與關聯性和優先級由以下語法,其運營商在列定義綴表達式優先

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; 
    } 
    }