1
void whatever() {
  // ...
  val parser = new MyParser
  val parse = parser.parse(input)
  if (parse successful) {
    semanticAnalysis(parse)
  }
}

void semanticAnalysis(parse: DontKnowTheCorrectType) {
  // ...
}

我必须给形式参数什么类型parse?将鼠标悬停在parse里面whateverval parse: parser.ParseResult[parsing.Program],但是这当然不能作为 的参数类型semanticAnalysis,因为局部变量parse不在此处的范围内。

4

4 回答 4

3

解析结果是依赖于路径的类型,因为它们是此特定解析器的结果,并且不能保证它们是兼容的。

这就是为什么解析器通常不会按照您使用它们的方式 ( new MyParser) 进行实例化,而是作为object.

object MyParser extends RegexParsers { 
   def statements : Parser[List[Statement]] = // ...
} 

def handleResult(res: MyParser.ParseResult[List[Statement]]) = { // ... } 

val res = MyParser.parseAll(MyParser.statements, "/* */")

如果您需要更多的动态行为(或者想要并发解析,解析器组合器不是线程安全的,哎哟),您只需要保持解析器对象可访问(且稳定),无论您想在哪里使用它的结果。

可悲的是,将解析器及其结果一起传递并不是一件容易的事,因为您会遇到依赖方法类型的禁令,例如

  def fun(p: scala.util.parsing.combinator.Parsers, res: p.ParseResult[_]) = {}

不会编译(“非法依赖方法类型”),但如果必须的话,有一些方法可以解决这个问题,比如这个问题的答案。

于 2012-08-21T09:41:06.460 回答
1

您应该能够定义semanticAnalysis为:

def semanticAnalysis(parse: MyParser#ParseResult[parsing.Program]) = {
  ...
}

注意类型的使用#而不是.这里有关于类型投影的更多细节,但基本上,parser.ParseResult每个都不同parser,而MyParser#ParseResult所有parser实例都相同。

但是,正如主题所说,您可能应该使用object而不是class.

于 2012-08-21T10:30:04.590 回答
0

你可以像这样重写它:

def whatever() {
  // ...
  val parser = new MyParser
  def semanticAnalysis(parse: parser.ParseResult) {
    // ...
  }
  val parse = parser.parse(input)
  if (parse successful) {
    semanticAnalysis(parse)
  }
}

如果您从多个地方调用它,那么可能是这样的:

  class SemanticAnalysis(parser: Parser) {
    def apply(parse: parser.ParseResult) {
      // ...
    }
  }

进而

  if (parse successful) {
    new SemanticAnalysis(parser)(parse)
  }
于 2012-08-21T20:51:59.697 回答
0

当我需要在程序的其他部分使用解析器组合器的结果时,我从路径依赖中提取成功结果或错误消息,ParseResult并将数据放入独立类型。它比我喜欢的更冗长,但我想将组合器实例保留为解析器的实现细节。

sealed abstract class Result[+T]
case class Success[T](result: T) extends Result[T]
case class Failure(msg: String) extends Result[Nothing]
case class Error(msg: String) extends Result[Nothing]

/** Parse the package declarations in the file. */
def parse(file: String): Result[List[Package]] = {
  val stream = ... // open the file...
  val parser = new MyParser
  val result = parser.parseAll(parser.packages, stream)   
  stream.close()
  result match {
    case parser.Success(packages, _) => Success(packages)
    case parser.Failure(msg, _) => Failure(msg)
    case parser.Error(msg, _) => Error(msg)
  }
}
于 2013-09-14T23:31:47.497 回答