2015-04-16 32 views
0

我想在scala中編寫一個簡單的解析器,但是當我添加重複的令牌時Scala似乎陷入了無限循環。scala解析器組合器無限循環

我有2個下面的解析方法。一個使用rep()。非重複版本按預期工作(不是我想要的),但使用rep()版本會導致無限循環。

編輯: 這是一個學習的例子,我厭倦了執行'='被空白包圍。

如果它是有幫助的,這是我的實際測試文件:

a = 1 
b = 2 
c = 1 2 3 

我能夠解析:(與parse1法) ķ= V

但隨後就遇到了這個問題,嘗試當擴大鍛煉出來: K = V1 V2 V3

import scala.util.parsing.combinator._ 
import scala.io.Source.fromFile 

class MyParser extends RegexParsers { 
    override def skipWhitespace(): Boolean = { false } 

    def key: Parser[String] = """[a-zA-Z]+""".r ^^ { _.toString } 
    def eq: Parser[String] = """\s+=\s+""".r ^^ { _.toString.trim } 
    def string: Parser[String] = """[^ \t\n]*""".r ^^ { _.toString.trim } 
    def value: Parser[List[String]] = rep(string) 

    def foo(key: String, value: String): Boolean = { 
    println(key + " = " + value) 
    true 
    } 

    def parse1: Parser[Boolean] = key ~ eq ~ string ^^ { case k ~ eq ~ string => foo(k, string) } 
    def parse2: Parser[Boolean] = key ~ eq ~ value ^^ { case k ~ eq ~ value => foo(k, value.toString) } 

    def parseLine(line: String): Boolean = { 
     parse(parse2, line) match { 
     case Success(matched, _) => true 
     case Failure(msg, _) => false 
     case Error(msg, _) => false 
    } 
    } 
} 

object TestParser { 
    def usage() = { 
    System.out.println("<file>") 
    } 

    def main(args: Array[String]) : Unit = { 
    if (args.length != 1) { 
     usage() 
    } else { 
     val mp = new MyParser() 

     fromFile(args(0)).getLines().foreach { mp.parseLine } 
     println("done") 
    } 
    } 
} 

回答

1

下一次,請提供一些具體的例子,這不是很明顯你的我輸入應該看起來像。

同時,你可以試試這個,也許你會發現它有用:

import scala.util.parsing.combinator._ 
import scala.io.Source.fromFile 

class MyParser extends JavaTokenParsers { 
    // override def skipWhitespace(): Boolean = { false } 

    def key: Parser[String] = """[a-zA-Z]+""".r ^^ { _.toString } 
    def eq: Parser[String] = "=" 
    def string: Parser[String] = """[^ \t\n]+""".r 
    def value: Parser[List[String]] = rep(string) 

    def foo(key: String, value: String): Boolean = { 
    println(key + " = " + value) 
    true 
    } 

    def parse1: Parser[Boolean] = key ~ eq ~ string ^^ { case k ~ eq ~ string => foo(k, string) } 
    def parse2: Parser[Boolean] = key ~ eq ~ value ^^ { case k ~ eq ~ value => foo(k, value.toString) } 

    def parseLine(line: String): Boolean = { 
     parseAll(parse2, line) match { 
     case Success(matched, _) => true 
     case Failure(msg, _) => false 
     case Error(msg, _) => false 
    } 
    } 
} 

val mp = new MyParser() 
for (line <- List("hey = hou", "hello = world ppl", "foo = bar baz blup")) { 
    println(mp.parseLine(line)) 
} 

說明:

JavaTokenParsers和RegexParsers區別對待空白。 JavaTokenParsers爲您處理空白空間,它不是特定於Java,它適用於大多數非深奧語言。只要你不試圖解析空白,JavaTokenParsers是一個很好的起點。

你的字符串定義包括一個*,它導致了無限遞歸。 您的eq定義包含與空白處理混淆的東西(除非真的有必要,否則不要這樣做)。 此外,如果你想解析整行,你必須調用parseAll, ,否則它只以非貪婪的方式解析字符串的開頭。

最後的備註:對於逐行解析鍵值對,一些String.split和 String.trim將是完全足夠的。 Scala Parser Combinator對此有點矯枉過正。

PS:嗯......你想允許= -signs在你的密鑰名中?然後我的版本在這裏不起作用,因爲它沒有在key-name之後強制執行一個空的空間。

+0

呃,我不應該遲疑。這是一個可怕的問題.... 我會更新,但是是的目標是寫一個解析器(用於學習),強制K = V與強制性空白。它看起來像一個簡單的初學者解析器。 – user2466803

+0

我不確定在這裏做什麼。看起來這個問題已經得到解答,但它沒有。這在很大程度上是我錯誤地提出這個問題的錯。是否有可能把Andrey Tyukin折騰出一些業力或者做出偉大的嘗試,但這仍然表明我被困在這裏? – user2466803

+0

再次。對不起,我沒有意識到你關心空白。我認爲這是關於'''''Parser'中的''''''''''''''''''''''的錯誤。我添加了明確照顧空白區域的另一個版本。 –

1

這是不是一個重複的,這是一個不同的版本RegexParsers這需要空白的照顧明確

如果出於某種原因真的關心空格,那麼你可以堅持RegexParsers,做如下(注意skipWhitespace = false,對空白ws明確的解析器,兩個ws與各地等號squiglies和repsep和顯式指定ws):

import scala.util.parsing.combinator._ 
import scala.io.Source.fromFile 

class MyParser extends RegexParsers { 
    override def skipWhitespace(): Boolean = false 

    def ws: Parser[String] = "[ \t]+".r 
    def key: Parser[String] = """[a-zA-Z]+""".r ^^ { _.toString } 
    def eq: Parser[String] = ws ~> """=""" <~ ws 
    def string: Parser[String] = """[^ \t\n]+""".r 
    def value: Parser[List[String]] = repsep(string, ws) 

    def foo(key: String, value: String): Boolean = { 
    print(key + " = " + value) 
    true 
    } 

    def parse1: Parser[Boolean] = (key ~ eq ~ string) ^^ { case k ~ e ~ v => foo(k, v) } 
    def parse2: Parser[Boolean] = (key ~ eq ~ value) ^^ { case k ~ e ~ v => foo(k, v.toString) } 

    def parseLine(line: String): Boolean = { 
     parseAll(parse2, line) match { 
     case Success(matched, _) => true 
     case Failure(msg, _) => false 
     case Error(msg, _) => false 
    } 
    } 
} 

val mp = new MyParser() 
for (line <- List("hey = hou", "hello = world ppl", "foo = bar baz blup", "foo= bar baz", "foo =bar baz")) { 
    println(" (Matches: " + mp.parseLine(line) + ")") 
} 

現在解析器拒絕哪裏有等號周圍沒有空白行:

hey = List(hou) (Matches: true) 
hello = List(world, ppl) (Matches: true) 
foo = List(bar, baz, blup) (Matches: true) 
(Matches: false) 
(Matches: false) 

*代替+string該bug已被刪除,就像在以前的版本。