EBNF

2009-02-08 6 views
11

मैं निम्नलिखित EBNF कि मैं पार्स करने के लिए करना चाहते हैं: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) का सहारा लेने के बिना।

उत्तर

12

मैं इस तरह यह करना होगा:

type E = Expression 

def postfixExp = primaryExp ~ rep(
    "[" ~> expr <~ "]" ^^ { e => ElementExpression(_:E, e) } 
    | "." ~ "length" ^^^ LengthExpression 
    | "." ~> ident ~ ("(" ~> repsep(expr, ",") <~ ")") ^^ flatten2 { (f, args) => 
     CallMethodExpression(_:E, f, args) 
    } 
) ^^ flatten2 { (e, ls) => collapse(ls)(e) } 

def expr: Parser[E] = ... 

def collapse(ls: List[E=>E])(e: E) = { 
    ls.foldLeft(e) { (e, f) => f(e) } 
} 

संक्षिप्तता के लिए expr करने के लिए expressions छोटा साथ ही एक ही कारण के लिए प्रकार उर्फ ​​E गयी।

बदसूरत केस विश्लेषण से बचने के लिए मैं जिस चाल का उपयोग कर रहा हूं वह फ़ंक्शन मान आंतरिक उत्पादन के भीतर से वापस करना है। यह फ़ंक्शन Expression (जो primary होगा) लेता है और फिर पहले के आधार पर एक नया Expression देता है। यह डॉट-प्रेषण और ब्रैकेट किए गए अभिव्यक्तियों के दो मामलों को एकीकृत करता है। अंत में, collapse विधि निर्दिष्ट प्राथमिक अभिव्यक्ति से शुरू होने वाले उचित एएसटी में फ़ंक्शन मानों के रैखिक List को मर्ज करने के लिए उपयोग की जाती है।

ध्यान दें कि LengthExpression को अपने संबंधित उत्पादन से केवल एक मान (^^^ का उपयोग करके) के रूप में वापस कर दिया गया है। यह काम करता है क्योंकि साथी वर्ग वर्गों के लिए वस्तुएं (मानते हैं कि LengthExpression वास्तव में एक केस क्लास है) उनके कन्स्ट्रक्टर को संबंधित संबंधित फ़ंक्शन वैल्यू का विस्तार करते हैं। इस प्रकार, LengthExpression द्वारा प्रस्तुत फ़ंक्शन एक Expression लेता है और LengthExpression का एक नया उदाहरण देता है, जो उच्च-आदेश वृक्ष निर्माण के लिए हमारी आवश्यकताओं को पूरी तरह से संतुष्ट करता है।