Scala 解析器组合器递归 bnf 的技巧?

2023-12-20

我试图匹配这个语法:

pgm ::= exprs
exprs ::= expr [; exprs]
expr ::= ID | expr . [0-9]+

我的 scala Packrat 解析器组合器如下所示:

import scala.util.parsing.combinator.PackratParsers
import scala.util.parsing.combinator.syntactical._

object Dotter extends StandardTokenParsers with PackratParsers {
    lexical.delimiters ++= List(".",";")
    def pgm = repsep(expr,";")
    def expr :Parser[Any]= ident | expr~"."~num
    def num = numericLit

       def parse(input: String) =
    phrase(pgm)(new PackratReader(new lexical.Scanner(input))) match {
      case Success(result, _) => println("Success!"); Some(result)
      case n @ _ => println(n);println("bla"); None
    }  

    def main(args: Array[String]) {
      val prg = "x.1.2.3;" +
            "y.4.1.1;" +
            "z;" +
            "n.1.10.30"


            parse(prg);
    }
}

但这行不通。要么它“匹配贪婪”并告诉我:

[1.2] failure: end of input expected 
x.1.2.3;y.4.1.1;z;n.1.10.30

或者如果我改变| to a |||我得到一个堆栈溢出:

Exception in thread "main" java.lang.StackOverflowError
at java.lang.Character.isLetter(Unknown Source)
at java.lang.Character.isLetter(Unknown Source)
at scala.util.parsing.combinator.lexical.Lexical$$anonfun$letter$1.apply(Lexical.scala:32)
at scala.util.parsing.combinator.lexical.Lexical$$anonfun$letter$1.apply(Lexical.scala:32)
...

我有点明白为什么我会收到这些错误;我该怎么做才能解析上面这样的语法?对我来说似乎并不那么深奥

编辑: 基于中引用的论文http://scala-programming-language.1934581.n4.nabble.com/Packrat-parser-guidance-td1956908.html http://scala-programming-language.1934581.n4.nabble.com/Packrat-parser-guidance-td1956908.html我发现我的程序实际上并没有使用新的 Packrat 解析器。

IE。改变Parser[Any] to PackratParser[Any]并使用lazy val代替def

我将上面的内容重写为:

import scala.util.parsing.combinator.PackratParsers
import scala.util.parsing.combinator.syntactical._

object Dotter extends StandardTokenParsers with PackratParsers {
    lexical.delimiters ++= List(".",";")
    lazy val pgm : PackratParser[Any] = repsep(expr,";")
    lazy val expr :PackratParser[Any]= expr~"."~num | ident
    lazy val num = numericLit

    def parse(input: String) =
    phrase(pgm)(new PackratReader(new lexical.Scanner(input))) match {
      case Success(result, _) => println("Success!"); Some(result)
      case n @ _ => println(n);println("bla"); None
    }  

    def main(args: Array[String]) {
      val prg = "x.1.2.3 ;" +
            "y.4.1.1;" +
            "z;" +
            "n.1.10.30"


            parse(prg);
    }
}

问题是(至少部分地)你实际上并没有使用 Packrat 解析器。请参阅 Scala 的文档Packrat 解析器 http://www.scala-lang.org/archives/downloads/distrib/files/nightly/docs/library/scala/util/parsing/combinator/PackratParsers.html特质,它说

使用 PackratParsers 非常相似 使用解析器:

  • 扩展解析器的任何类/特征(直接或通过 子类)可以混合在 PackratParsers 中。 示例:对象 MyGrammar 扩展 标准令牌解析器 Packrat解析器
  • 每个语法产生式之前都声明为 def,但没有 形式参数变成惰性值, 它的类型从 Parser[Elem] 到 PackratParser[Elem]。 例如,def 生产: Parser[Int] = {...} 变为惰性 val 生产:PackratParser[Int] = {...}
  • 重要提示:使用 Packrat 解析器并不是一个全有或全无的决定。它们可以在单个语法中与常规解析器自由混合。

我对 Scala 2.8 的解析器组合器了解不够,无法完全解决这个问题,但通过以下修改,我能够让它解析到分号,这比您已完成的工作有所改进。

object Dotter extends StandardTokenParsers with PackratParsers {
    lexical.delimiters ++= List(".",";")
    lazy val pgm:PackratParser[Any] = repsep(expr,";")
    lazy val expr:PackratParser[Any]= ident ||| (expr~"."~numericLit)

    def parse(input: String) = phrase(expr)(lex(input)) match {
      case Success(result, _) => println("Success!"); Some(result)
      case n @ _ => println(n);println("bla"); None
    }  

    def lex(input:String) = new PackratReader(new lexical.Scanner(input))
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Scala 解析器组合器递归 bnf 的技巧? 的相关文章

随机推荐