2009-11-23 26 views
7

मैं एक ऐसा एप्लीकेशन लिख रहा हूं जो विभिन्न "कमांड" तारों में लगेगा। मैं आदेशों को टोकन करने के लिए स्कैला संयोजक पुस्तकालय को देख रहा हूं। मुझे कई मामलों में लगता है कि मैं कहना चाहता हूं: "ये टोकन एक ऑर्डरलेस सेट हैं, और इसलिए वे किसी भी क्रम में दिखाई दे सकते हैं, और कुछ दिखाई नहीं दे सकते हैं"।ग्रामर, स्कैला पार्सिंग कॉम्बिनेटर्स और ऑर्डरलेस सेट

व्याकरण के अपने मौजूदा ज्ञान के साथ

मैं ऐसे (छद्म व्याकरण) के रूप में दृश्यों के सभी संयोजनों को परिभाषित करने के लिए होगा:

command = action~content 
action = alphanum 
content = (tokenA~tokenB~tokenC | tokenB~tokenC~tokenA | tokenC~tokenB~tokenA .......) 

तो मेरे सवाल है, पर विचार tokenA-सी अद्वितीय हैं, वहाँ एक छोटा रास्ता है एक व्याकरण का उपयोग कर किसी भी आदेश के एक सेट को परिभाषित करने के लिए?

उत्तर

3

इसके आसपास के तरीके हैं। उदाहरण के लिए पार्सर here पर एक नज़र डालें। यह 4 पूर्व परिभाषित संख्या स्वीकार करता है, जो कि किसी अन्य में प्रकट हो सकता है, लेकिन एक बार प्रकट होना चाहिए, और केवल एक बार।

OTOH, आप एक Combinator लिख सकता है अगर इस पद्धति अक्सर ऐसा होता है:

def comb3[A](a: Parser[A], b: Parser[A], c: Parser[A]) = 
    a ~ b ~ c | a ~ c ~ b | b ~ a ~ c | b ~ c ~ a | c ~ a ~ b | c ~ b ~ a 
0

आप निश्चित रूप से संयोजन नियम लिख सकते हैं जो आपके लिए यह स्थिति करता है यदि आप अक्सर इस स्थिति का सामना करते हैं।

दूसरी ओर, शायद विकल्प "tokenA..C" बस "टोकन" बनाने के लिए और उसके बाद का हैंडलर के अंदर अंतर मौजूद है "टोकन"

+0

इस मामले में प्रत्येक टोकन एक जेसन शैली वस्तु संपत्ति है। तो एक आदेश "टोडो संदेश: लिंक टोडो क्लास को डेटाबेस" जैसा दिख सकता है: देय: अगले tuesday "। तो स्कैला शैली में परिभाषित सामान्य नियम" टोकन = अल्फानम ~ ':' ~ repsep (अल्फानम, '') जैसा कुछ है। लेकिन मुझे विशिष्ट गुणों को अलग-अलग संभालने की आवश्यकता है। –

+0

और आपको यह सुनिश्चित करना होगा कि वही एक से अधिक बार नहीं होता है? – ziggystar

+0

हाँ यह योजना है, कुछ गुण वैकल्पिक हैं, और उन्हें केवल एक बार होना चाहिए। –

0

मैं नहीं जानता कि निर्माणों की किस तरह आप चाहते हैं समर्थन करने के लिए, लेकिन मैं इकट्ठा करता हूं कि आपको एक और विशिष्ट व्याकरण निर्दिष्ट करना चाहिए।

कार्य करने की संदेश: एक और जवाब देने के लिए अपनी टिप्पणी से डेटाबेस के लिए लिंक तोदो वर्ग

मुझे लगता है कि आप

कार्य करने की संदेश की तरह कुछ स्वीकार करने के लिए नहीं करना चाहते हैं: करने के लिए डेटाबेस तोदो लिंक क्लास

तो शायद आप कुछ लिंक-स्तर वाले कीवर्ड जैसे "लिंक" और "टू" को परिभाषित करना चाहते हैं ...

def token = alphanum~':'~ "link" ~ alphanum ~ "class" ~ "to" ~ alphanum 
    ^^ { (a:String,b:String,c:String) => /* a == "message", b="Todo", c="database" */ } 

मुझे लगता है कि आपको उस स्तर पर अपने व्याकरण को परिभाषित करना होगा।

1

मैं वाक्य रचना इस आवश्यकता को लागू करने के लिए कोशिश नहीं करेंगे। मैं एक ऐसा उत्पादन लिखूंगा जो सेट से कई टोकन स्वीकार करता है और फिर वास्तव में दिए गए कीवर्ड की स्वीकार्यता का पता लगाने के लिए एक गैर-पार्सिंग दृष्टिकोण का उपयोग करता है। एक सरल व्याकरण की अनुमति देने के अलावा, यह आपको गलत उपयोग के बारे में निदान उत्सर्जित करने के बाद पार्सिंग को और अधिक आसानी से जारी रखने की अनुमति देगा।

रान्डेल शुल्ज

4

आप "पार्सर। ^?" उपयोग कर सकते हैं डुप्लिकेट के लिए पार्स तत्वों के समूह की जांच करने के लिए ऑपरेटर।

def tokens = tokenA | tokenB | tokenC 
    def uniqueTokens = (tokens*) ^? (
    { case t if (t == t.removeDuplicates) => t }, 
    { "duplicate tokens found: " + _ }) 

यहाँ एक उदाहरण है कि आप किसी भी क्रम में चार स्टूजेस में से किसी में प्रवेश करने की अनुमति देता है, लेकिन अगर कोई डुप्लिकेट का सामना करना पड़ा है पार्स करने के लिए विफल रहता है:

package blevins.example 

import scala.util.parsing.combinator._ 

case class Stooge(name: String) 

object StoogesParser extends RegexParsers { 
    def moe = "Moe".r 
    def larry = "Larry".r 
    def curly = "Curly".r 
    def shemp = "Shemp".r 
    def stooge = (moe | larry | curly | shemp) ^^ { case s => Stooge(s) } 
    def certifiedStooge = stooge | """\w+""".r ^? (
    { case s: Stooge => s }, 
    { "not a stooge: " + _ }) 

    def stooges = (certifiedStooge*) ^? (
    { case x if (x == x.removeDuplicates) => x.toSet }, 
    { "duplicate stooge in: " + _ }) 

    def parse(s: String): String = { 
    parseAll(stooges, new scala.util.parsing.input.CharSequenceReader(s)) match { 
     case Success(r,_) => r.mkString(" ") 
     case Failure(r,_) => "failure: " + r 
     case Error(r,_) => "error: " + r 
    } 
    } 

} 

और कुछ उदाहरण उपयोग:

package blevins.example 

object App extends Application { 

    def printParse(s: String): Unit = println(StoogesParser.parse(s)) 

    printParse("Moe Shemp Larry") 
    printParse("Moe Shemp Shemp") 
    printParse("Curly Beyonce") 

    /* Output: 
    Stooge(Moe) Stooge(Shemp) Stooge(Larry) 
    failure: duplicate stooge in: List(Stooge(Moe), Stooge(Shemp), Stooge(Shemp)) 
    failure: not a stooge: Beyonce 
    */ 
}