2009-11-23 11 views
7

Piszę aplikację, która będzie przyjmować różne ciągi "polecenia". Szukałem w bibliotece kombinatorów Scala, aby tokenizować polecenia. W wielu przypadkach chciałbym powiedzieć: "Te żetony są zbiorem bez porządku, więc mogą pojawić się w dowolnej kolejności, a niektóre mogą się nie pojawić".Gramatyki, parsujące kombinatory i zestawy bez sortowania

Z mojej obecnej wiedzy gramatyk musiałbym określić wszystkie kombinacje sekwencji jako takiej (gramatyki pseudo):

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

Więc moje pytanie jest, biorąc pod uwagę tokenA-C są unikatowe, istnieje krótsza droga zdefiniować zestaw dowolnych zamówień za pomocą gramatyki?

Odpowiedz

3

Istnieją sposoby obejścia tego. Spójrz na przykład na analizator składni here. Akceptuje 4 predefiniowane liczby, które mogą pojawić się w dowolnym innym, ale muszą pojawić się tylko raz i tylko jeden raz.

OTOH, można napisać COMBINATOR, jeśli ten wzór zdarza się często:

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

Można oczywiście napisać regułę kombinacji, która robi to za Ciebie, jeśli często napotykasz tę sytuację.

Z drugiej strony, być może istnieje opcja, aby „tokenA..C” tylko „znak”, a następnie różnicować wewnątrz przewodnika z „żeton”

+0

W tym przypadku każdy token jest właściwością obiektu w stylu json. Polecenie może więc wyglądać tak: "wiadomość todo: link Todo class to database", ponieważ: next wtorek. "Tak więc ogólna reguła zdefiniowana w scala stylu jest podobna do" token = alphanum ~ ": '~ repsep (alphanum,' '). Ale muszę inaczej obsługiwać określone właściwości. –

+0

Musisz się upewnić, że to samo nie występuje więcej niż raz? – ziggystar

+0

Tak, to jest plan, niektóre właściwości są opcjonalne i powinny wystąpić tylko raz. –

0

nie wiem jaki rodzaj konstrukcji chcesz do wsparcia, ale uważam, że powinieneś określać bardziej szczegółową gramatykę. Z komentarzem do innej odpowiedzi:

todo wiadomość: Todo klasy Link do bazy

Chyba nie chcesz, aby zaakceptować coś takiego komunikatu

todo: Todo do bazy danych link class

Prawdopodobnie chcesz zdefiniować niektóre słowa kluczowe na poziomie komunikatu, takie jak "link" i "to" ...

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

Sądzę, że musiałbyś zdefiniować swoją gramatykę na tym poziomie.

1

nie będę próbować wyegzekwować ten wymóg składniowo. Napisałbym produkcję, która dopuszcza wielokrotne tokeny ze zbioru, a następnie stosuje metodę nie parsowania w celu ustalenia akceptowalności słów kluczowych faktycznie podanych. Oprócz umożliwienia prostszej gramatyki, łatwiej będzie kontynuować analizę po wysłaniu diagnozy o błędnym użyciu.

Randall Schulz

4

Można użyć "Parser. ^?" operator, aby sprawdzić grupę elementów parsowanych dla duplikatów.

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

Oto przykład, który pozwala wprowadzić dowolny z czterech Stooges w dowolnej kolejności, ale nie do analizowania, czy duplikat napotkaniu:

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

} 

A niektóre z przykładów użycia:

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 
    */ 
} 
Powiązane problemy