有没有办法将上下文信息传递给解析器?

时间:2014-01-02 14:38:53

标签: scala parser-combinators

我正在解析一个小的声明性语言,在一个范围内你可以声明变量(带有一个类型),然后再使用,就像在大多数其他语言中一样,使用名称(没有类型)。

变量声明如下:

?varname
?varname1 ?varname2 - type1
?varname3 ?varname4 ?varname5 - type2

如果省略类型,则默认类型应为object,与第一种情况类似。 所以为此我有一个特定的解析器,它返回一个我自己的域对象列表,名为LiftedTerm(你可以假设它的元组有变量的名称和变量的类型,实际上还有一些其中的东西,但与此问题无关):

def typed_list_variables : Parser[List[LiftedTerm]]= typed_variables.+ ^^ { case list => list.flatten.map(variable =>
        LiftedTerm(variable._1, variable._2 match {
          case "object" => ObjectType
          case _ => TermType(variable._2)
        })) }

def typed_variables = ((variable+) ~ (("-" ~> primitive_type)?)) ^^ {
    case variables ~ primitive_type => 
         for (variable <- variables) yield variable -> primitive_type.getOrElse("object")
}

def variable = """\?[a-zA-Z][a-zA-Z0-9_-]*""".r
def primitive_type = """[a-zA-Z][a-zA-Z0-9_-]*""".r

这一切都很好。

现在在相同的“范围”中进一步向下,我必须解析存在对这些变量的引用的部分。该变量显然不会再次完整声明。因此,在上面的示例中,使用?varname1的地方不会包含type1。但是,当我解析其余的输入时,我希望得到正确的LiftedTerm对象的引用,而不仅仅是一个字符串。

我有一些递归结构,所以我不希望在顶级解析器上进行这种映射。我不希望在我的RegexParsers对象中对这些进行“全局映射”,因为大多数这些都是作用域的,只与输入的一小部分相关。

有没有办法将上下文信息传递给解析器?理想情况下,我将LiftedTerm(或者更好的是变量名称String -> LiftedTerm中的映射)列表传递给递归解析器调用。

(道歉,如果这是显而易见的事情,我仍然是Scala的新手,甚至是解析器组合器的新手。)

2 个答案:

答案 0 :(得分:1)

AFAIK,scala的组合子解析器库仅限于无上下文语法。因此,不支持您的用例。

正确的方法是扩展scala.util.parsing.combinator.Parsers并提供一个自定义Parser类,其中包含您的上下文。比你需要定义所有组合器以处理上下文。

编辑:正如下面所指出的,解析器有一个方法intoflatMap,因此,当你有一个产生上下文的解析器时,你可以将它与另一个需要一个解析器的解析器结合起来。一元风格的语境。

答案 1 :(得分:0)

&#34;有没有办法将上下文信息传递给解析器?&#34;是。例如,这里是lambda演算的玩具实现,它会删除变量名称。

case class Lam(bod: LambdaExp) extends LambdaExp
case class Var(v: Int) extends LambdaExp {
  require(v >= 0)
}
case class App(f: LambdaExp, a: LambdaExp) extends LambdaExp

sealed trait LambdaExp

可以用

解析
class LambdaParser extends RegexParsers {

  def varName: Parser[String] = """[a-z|A-Z]+""".r

  def variable(ctx: List[String]): Parser[Var] = varName ^? ({ case name if ctx.contains(name) => Var(ctx.indexOf(name)) }, { name => s"no var in scope with name $name" })

  def scope(v: String, ctx: List[String]): Parser[LambdaExp] = (("." ~> exp(v :: ctx))) ^^ { case bod => bod }

  def lam(ctx: List[String]): Parser[Lam] = (("λ" ~> varName) >> { v => scope(v, ctx) }) ^^ { scope => Lam(scope) }

  def app(ctx: List[String]): Parser[App] = (exp(ctx) ~ exp(ctx)) ^^ { case f ~ a => App(f, a) }

  def exp(ctx: List[String]): Parser[LambdaExp] = ("(" ~> exp(ctx) <~ ")") | ("(" ~> app(ctx) <~ ")") |
    variable(ctx) | lam(ctx)

}

请注意通过解析传递的上下文信息。