2009-11-23 13 views
7

Estoy escribiendo una aplicación que incluirá varias cadenas de "comandos". He estado buscando en la biblioteca del combinador de Scala para tokenizar los comandos. En muchos casos, me gustaría decir: "Estos tokens son un conjunto sin orden, por lo que pueden aparecer en cualquier orden y algunos pueden no aparecer".Gramáticas, Combinadores de análisis Scala y conjuntos sin orden

Con mi conocimiento actual de las gramáticas que tendría que definir todas las combinaciones de secuencias como tal (pseudo gramática):

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

Así que mi pregunta es, considerando tokenA-C son únicos, es que hay un camino más corto para definir un conjunto de cualquier orden usando una gramática?

Respuesta

3

Hay formas de evitarlo. Eche un vistazo al analizador here, por ejemplo. Acepta 4 números predefinidos, que pueden aparecer en cualquier otro, pero deben aparecer una vez y solo una vez.

otoh, se podría escribir un combinador, si este patrón ocurre a menudo:

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

Por supuesto, podría escribir una regla de combinación que lo haga por usted si se encuentra con esta situación con frecuencia.

Por otro lado, tal vez existe la opción de hacer "tokenA..C" sólo "token" y luego diferenciar dentro del manejador de "token"

+0

En este caso, cada token es una propiedad de objeto de estilo json. Así que un comando podría parecerse a "mensaje de todo: vincular clase Todo a la base de datos": el próximo martes ". Por lo tanto, la regla genérica definida en estilo scala es algo así como" token = alphanum ~ ':' ~ repsep (alphanum, ''). Pero sí necesito manejar propiedades específicas de manera diferente. –

+0

Y debes asegurarte de que el mismo no se repita más de una vez. – ziggystar

+0

Sí, ese es el plan, algunas propiedades son opcionales y solo deberían aparecer una vez. –

0

No sé qué tipo de construcciones que desea para apoyar, pero creo que deberías especificar una gramática más específica. Desde su comentario a otra respuesta:

TODO mensaje: Clase de enlace a la base de datos Todo

supongo que no quiere aceptar algo como mensaje

TODO: base de datos de Todo clase enlace

Así que es probable que desee para definir algunas palabras clave a nivel de mensaje como "enlace" y "a" ...

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

Supongo que tendrá que definir su gramática en ese nivel.

1

no intentaría hacer cumplir este requisito sintácticamente. Escribiría una producción que admite múltiples tokens del conjunto permitido y luego utilizaría un enfoque sin análisis para determinar la aceptabilidad de las palabras clave realmente dadas. Además de permitir una gramática más simple, le permitirá continuar analizando más fácilmente después de emitir un diagnóstico sobre el uso erróneo.

Randall Schulz

4

Usted puede utilizar el "Analizador. ^?" operador para verificar un grupo de elementos de análisis para duplicados.

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

Aquí es un ejemplo que le permite entrar en cualquiera de los cuatro chiflados en cualquier orden, pero no puede analizar si se encuentra un duplicado:

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

} 

Y algunos ejemplo de uso:

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