2009-11-23 12 views
7

Je suis en train d'écrire une application qui va prendre diverses chaînes "command". J'ai regardé la bibliothèque combinatoire de Scala pour marquer les commandes. Je trouve dans beaucoup de cas que je veux dire: "Ces jetons sont un ensemble sans ordre, et ils peuvent donc apparaître dans n'importe quel ordre, et certains peuvent ne pas apparaître".Grammars, Scala Combinators et Orderless Sets

Avec mes connaissances actuelles de grammaires, je dois définir toutes les combinaisons de séquences en tant que telle (pseudo grammaire):

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

Donc ma question est, étant donné tokenA-C sont uniques, est-il un moyen plus court définir un ensemble de n'importe quel ordre en utilisant une grammaire?

Répondre

3

Il existe des moyens de contourner cela. Jetez un oeil à l'analyseur here, par exemple. Il accepte 4 nombres prédéfinis, qui peuvent apparaître dans n'importe quel autre, mais doivent apparaître une fois, et une seule fois.

OTOH, vous pouvez écrire un combinateur, si ce modèle arrive souvent:

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

Vous pouvez bien sûr écrire une règle de combinaison qui le fait pour vous si vous rencontrez fréquemment cette situation.

D'autre part, peut-être l'option existe pour faire « tokenA..C » juste « jeton » puis différencier dans le gestionnaire de « jeton »

+0

Dans ce cas, chaque jeton est une propriété d'objet de style json. Ainsi, une commande pourrait ressembler à "todo message: lier Todo class à la base de données" en raison de: mardi prochain "Donc la règle générique définie dans le style scala est quelque chose comme" token = alphanum ~ ':' ~ repsep (alphanum, ''). Mais j'ai besoin de gérer des propriétés spécifiques différemment. –

+0

Et vous devez vous assurer, que le même ne se produit pas plus d'une fois? – ziggystar

+0

Oui, c'est le plan, certaines propriétés sont facultatives, et elles ne devraient avoir lieu qu'une seule fois. –

0

Je ne sais pas quel genre de constructions que vous voulez à soutenir, mais je suppose que vous devriez spécifier une grammaire plus spécifique. De votre commentaire à une autre réponse:

todo message: lien classe Todo à la base de données

Je suppose que vous ne voulez pas accepter quelque chose comme

todo message: base de données Todo à classe de liens

Vous voulez donc probablement définir des mots-clés au niveau du message comme "link" et "to" ...Je suppose que vous devriez définir votre grammaire à ce niveau.

1

Je ne voudrais pas essayer de faire respecter cette exigence syntaxiquement. J'écrirais une production qui admettrait plusieurs jetons de l'ensemble autorisé, puis j'utiliserais une approche sans analyse pour vérifier l'acceptabilité des mots clés réellement donnés. En plus de permettre une grammaire plus simple, cela vous permettra de continuer plus facilement l'analyse après avoir émis un diagnostic sur l'utilisation erronée.

Randall Schulz

4

Vous pouvez utiliser la fonction "Parser. ^?" opérateur pour vérifier un groupe d'éléments d'analyse pour les doublons.

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

Voici un exemple qui vous permet d'entrer dans l'une des quatre larbins dans l'ordre, mais ne parvient pas à analyser si un double est rencontré:

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

} 

Et une utilisation exemple:

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