Eug*_*ota 16 parsing scala parser-combinators
给定一系列实现解析器组合器的对象,如何组合解析器?由于Parsers.Parser是一个内部类,并且在Scala 内部类中绑定到外部对象,故事变得有点复杂.
这是一个尝试组合来自不同对象的两个解析器的示例.
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) ))
}
}
Run Code Online (Sandbox Code Playgroud)
这导致以下错误:
<console>:11: error: type mismatch;
found : ShortChainParser.Parser[Any]
required: LongChainParser.Parser[?]
def parser: Parser[Any] = (LongChainParser.parser1
||| ShortChainParser.parser2) ~ anyrep
Run Code Online (Sandbox Code Playgroud)
我已经找到了解决这个问题的方法,但是由于它是最近在scala-user ML上提出的(问题是将一个解析器注入另一个),所以它也可能值得把它放在这里.
Eug*_*ota 17
快速回答是使用traits而不是在s中托管解析器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) ))
}
}
Run Code Online (Sandbox Code Playgroud)
因为组合运算符喜欢~并且|是针对内部类编写的,所以通过说法将解析器引用升级为类级别BinaryParser#Parser[_]对你没有任何好处.使用特性解决了所有的内部类的问题,因为两者Parser[Any]从LongChainParser和ShortChainParser现在所说的内部类的ExampleParser对象.