2010-04-16 4 views
15

Étant donné une famille d'objets qui implémentent des combinateurs d'analyseurs, comment combiner les analyseurs syntaxiques? Puisque Parsers.Parser est une classe interne, et dans Scala inner classes are bound to the outer object, l'histoire devient légèrement compliquée.Scala: comment combiner des combinateurs d'analyseurs à partir d'objets différents

Voici un exemple qui tente de combiner deux analyseurs d'objets différents.

import scala.util.parsing.combinator._ 

class BinaryParser extends JavaTokenParsers { 
    def anyrep: Parser[Any] = rep(any) 
    def any: Parser[Any] = zero | one 
    def zero: Parser[Any] = "0" 
    def one: Parser[Any] = "1" 
} 

object LongChainParser extends BinaryParser { 
    def parser1: Parser[Any] = zero~zero~one~one 
} 

object ShortChainParser extends BinaryParser { 
    def parser2: Parser[Any] = zero~zero 
} 

object ExampleParser extends BinaryParser { 
    def parser: Parser[Any] = (LongChainParser.parser1 
    ||| ShortChainParser.parser2) ~ anyrep 

    def main(args: Array[String]) { 
    println(parseAll(parser, args(0))) 
    } 
} 

Il en résulte de l'erreur suivante:

<console>:11: error: type mismatch; 
found : ShortChainParser.Parser[Any] 
required: LongChainParser.Parser[?] 
     def parser: Parser[Any] = (LongChainParser.parser1 
      ||| ShortChainParser.parser2) ~ anyrep 

que j'ai trouvé la solution à ce problème déjà, mais depuis qu'il a été élevé récemment sur scala utilisateur ML (Problem injecting one parser into another), il est vaut probablement le mettre ici aussi.

Répondre

17

La réponse rapide est d'utiliser les trait s au lieu d'accueillir les parseurs object s:

import scala.util.parsing.combinator._ 

trait BinaryParser extends JavaTokenParsers { 
    def anyrep: Parser[Any] = rep(any) 
    def any: Parser[Any] = zero | one 
    def zero: Parser[Any] = "0" 
    def one: Parser[Any] = "1" 
} 

trait LongChainParser extends BinaryParser { 
    def parser1: Parser[Any] = zero~zero~one~one 
} 

trait ShortChainParser extends BinaryParser { 
    def parser2: Parser[Any] = zero~zero 
} 

object ExampleParser extends LongChainParser with ShortChainParser { 
    def parser: Parser[Any] = (parser1 ||| parser2) ~ anyrep 

    def main(args: Array[String]) { 
    println(parseAll(parser, args(0))) 
    } 
} 

Parce que les opérateurs de Combinator comme ~ et | sont écrits contre la classe intérieure, l'escalade des références de l'analyseur à la classe -level en disant BinaryParser#Parser[_] ne vous fait aucun bien. L'utilisation de traits résout tous ces problèmes de classes internes puisque les deux Parser[Any] de LongChainParser et ShortChainParser font maintenant référence à la classe interne de l'objet ExampleParser.

+1

Merci de poster cette question et bien sûr d'y répondre! Ceci est exactement ce que je cherchais. –

Questions connexes