代码之家  ›  专栏  ›  技术社区  ›  Eugene Yokota

scala:如何组合来自不同对象的解析器组合器

  •  16
  • Eugene Yokota  · 技术社区  · 14 年前

    给定一系列实现解析器组合器的对象,如何组合解析器?自从 Parsers.Parser 是一个内部类,在scala中 inner classes are bound to the outer object 故事变得有点复杂。

    下面是一个尝试组合来自不同对象的两个解析器的示例。

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

    这将导致以下错误:

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

    我已经找到了解决这个问题的办法,但自从它被提出后 最近在scala用户ml上( Problem injecting one parser into another )可能也值得放在这里。

    1 回复  |  直到 14 年前
        1
  •  17
  •   Eugene Yokota    14 年前

    快速的答案是使用 trait 而不是将解析器托管在 object

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

    因为组合运算符喜欢 ~ | 是针对内部类编写的,通过说 BinaryParser#Parser[_] 对你没有好处。使用特性可以解决所有的内部类问题,因为两者都有 Parser[Any] LongChainParser ShortChainParser 现在指的是 ExampleParser 对象。