在scala中对递归解析器的高级控制

时间:2010-05-12 08:47:48

标签: parsing scala parser-combinators

val uninterestingthings = ".".r
val parser = "(?ui)(regexvalue)".r | (uninterestingthings~>parser)

这个递归解析器将尝试解析“(?ui)(regexvalue)”。r直到输入结束。在scala中,当“不感兴趣”消耗某些定义数量的字符时,禁止解析吗?

UPD:我有一个糟糕的解决方案:

object NonRecursiveParser extends RegexParsers with PackratParsers{
  var max = -1
  val maxInput2Consume = 25
  def uninteresting:Regex ={
    if(max<maxInput2Consume){
    max+=1
    ("."+"{0,"+max.toString+"}").r
    }else{
      throw new Exception("I am tired")
    }
  }
  lazy val value = "itt".r
  def parser:Parser[Any] = (uninteresting~>value)|parser
  def parseQuery(input:String) = {
      try{
      parse(parser, input)
      }catch{
          case e:Exception => 
      }
  }
}

缺点:
- 并非所有成员都是懒惰的,所以PackratParser会有一些时间的惩罚 - 在每个“无趣的”方法调用上构建正则表达式 - 时间惩罚
- 使用异常来控制程序 - 代码风格和时间损失

2 个答案:

答案 0 :(得分:3)

快速和肮脏的回答是只限制你的正则表达式中的字符数量以获得无趣感并使其不是递归的:

val uninterestingthings = ".{0,60}".r  // 60-chars max
val parser = (uninterestingthings~>"(?ui)(regexvalue)".r)*

基于关于贪婪吃正义指数的评论,我提出了一个正则表达式:

val parser = ("(?.{0,60}?)(?ui)(regexvalue)".r)*

但是我们似乎已经在scala解析器之外冒险进入正则表达式细节。我有兴趣看到其他结果。

答案 1 :(得分:0)

使用标记生成器首先解决问题,使用所有正则表达式来处理您已经知道的有趣事情。如果它们对您的语法很重要,请使用单个".".r来匹配无趣的事物。 (或者如果它们对语法没有意义,就扔掉它们。)你有趣的东西现在已经知道了类型,并且它们由标记器使用与解析不同的算法识别。由于所有前瞻问题都是由tokenizer解决的,因此解析器应该很容易。