2009-11-23 16 views
7

Sto scrivendo un'applicazione che includerà varie stringhe di "comando". Stavo guardando la libreria del combinatore di Scala per tokenizzare i comandi. Trovo in molti casi che voglio dire: "Questi token sono un set senza ordine, e quindi possono apparire in qualsiasi ordine, e alcuni potrebbero non apparire".Grammatic, Combinatori di analisi alla scala e set privi di ordini

Con la mia attuale delle conoscenze delle grammatiche avrei dovuto definire tutte le combinazioni di sequenze in quanto tali (pseudo grammatica):

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

Quindi la mia domanda è, considerando tokenA-C sono unici, c'è un modo più breve definire un insieme di qualsiasi ordine usando una grammatica?

risposta

3

Ci sono molti modi per aggirarlo. Dai un'occhiata al parser here, per esempio. Accetta 4 numeri predefiniti, che possono apparire in qualsiasi altro, ma devono apparire una volta e solo una volta.

OTOH, si potrebbe scrivere un combinatore, se questo schema spesso accade:

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

Si potrebbe ovviamente scrivere una regola di combinazione che fa questo per te se incontri questa situazione frequentemente.

D'altra parte, forse esiste la possibilità di fare "tokenA..C" solo "token" e quindi differenziarsi all'interno del gestore di "token"

+0

In questo caso ogni token è una proprietà dell'oggetto in stile json. Quindi un comando potrebbe apparire come "todo message: link Todo class to database" a causa: martedì prossimo ". Quindi la regola generica definita in scala style è qualcosa come" token = alphanum ~ ':' ~ repsep (alphanum, ''). Ma ho bisogno di gestire le proprietà specifiche in modo diverso. –

+0

E devi assicurarti che lo stesso non si verifichi più di una volta? – ziggystar

+0

Sì, questo è il piano, alcune proprietà sono opzionali e dovrebbero verificarsi solo una volta. –

0

Non so che tipo di costrutti che si desidera per supportare, ma ho capito che dovresti specificare una grammatica più specifica. Dal tuo commento a un'altra risposta:

todo un messaggio: classe di collegamento alla base di dati Todo

Credo che non si vuole accettare qualcosa come messaggio

todo: banca dati per Todo link classe

Quindi probabilmente si desidera definire alcune parole chiave a livello di messaggio come "link" e "a" ...

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

Immagino che dovresti definire la tua grammatica a quel livello.

1

non vorrei cercare di far rispettare questo requisito sintatticamente. Scriverò una produzione che ammette più token dal set consentito e quindi utilizzare un approccio non-analisi per accertare l'accettabilità delle parole chiave effettivamente fornite. Oltre a consentire una grammatica più semplice, ti permetterà di continuare più facilmente l'analisi dopo aver emesso una diagnostica sull'uso errato.

Randall Schulz

4

È possibile utilizzare la "Parser. ^?" operatore per controllare un gruppo di elementi di analisi per i duplicati.

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

Ecco un esempio che consente di inserire uno dei quattro tirapiedi in qualsiasi ordine, ma non riesce ad analizzare se viene rilevato un duplicato:

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

} 

E alcuni esempio di utilizzo:

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