我正在解析一个小的声明性语言,在一个范围内你可以声明变量(带有一个类型),然后再使用,就像在大多数其他语言中一样,使用名称(没有类型)。
变量声明如下:
?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的新手,甚至是解析器组合器的新手。)
答案 0 :(得分:1)
AFAIK,scala的组合子解析器库仅限于无上下文语法。因此,不支持您的用例。
正确的方法是扩展scala.util.parsing.combinator.Parsers
并提供一个自定义Parser
类,其中包含您的上下文。比你需要定义所有组合器以处理上下文。
编辑:正如下面所指出的,解析器有一个方法into
和flatMap
,因此,当你有一个产生上下文的解析器时,你可以将它与另一个需要一个解析器的解析器结合起来。一元风格的语境。
答案 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)
}
请注意通过解析传递的上下文信息。