svr*_*ist 6 scala ebnf parser-combinators
我试图匹配这种语法:
pgm ::= exprs
exprs ::= expr [; exprs]
expr ::= ID | expr . [0-9]+
Run Code Online (Sandbox Code Playgroud)
我的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);
}
}
Run Code Online (Sandbox Code Playgroud)
但这不起作用.要么"匹配贪婪"并告诉我:
[1.2] failure: end of input expected
x.1.2.3;y.4.1.1;z;n.1.10.30
Run Code Online (Sandbox Code Playgroud)
或者,如果我更改|为a,|||我得到一个stackoverflow:
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)
...
Run Code Online (Sandbox Code Playgroud)
我理解为什么我会得到错误; 我该怎么做才能解析上面的语法?对我来说似乎并不深奥
编辑:根据http://scala-programming-language.1934581.n4.nabble.com/Packrat-parser-guidance-td1956908.html中引用的论文, 我发现我的程序实际上没有使用新的packrat解析器.
IE浏览器.更改Parser[Any]到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);
}
}
Run Code Online (Sandbox Code Playgroud)
Ken*_*oom 10
问题是(至少部分地)你实际上并没有使用Packrat解析器.请参阅Scala的PackratParsers特性文档
使用PackratParsers非常类似于使用Parsers:
- 任何扩展Parsers(直接或通过子类)的类/特性都可以混合使用PackratParsers.示例:object MyGrammar使用PackratParsers扩展StandardTokenParsers
- 之前声明为没有形式参数的def的每个语法生成变为惰性val,其类型从Parser [Elem]更改为PackratParser [Elem].因此,例如,def生产:Parser [Int] = {...}变得懒惰生产:PackratParser [Int] = {...}
- 重要提示:使用PackratParsers不是一个全有或全无的决定.它们可以与单个语法中的常规解析器自由混合.
我不太了解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))
}
Run Code Online (Sandbox Code Playgroud)