2010-03-05 17 views
7

Tôi đang thử nghiệm với các trình kết hợp phân tích cú pháp và tôi thường chạy vào những gì có vẻ như các cuộc truy tìm vô hạn. Đây là lần đầu tiên tôi gặp phải:Trình kết hợp phân tích cú pháp không chấm dứt - cách đăng nhập những gì đang diễn ra?

import util.parsing.combinator.Parsers 
import util.parsing.input.CharSequenceReader 

class CombinatorParserTest extends Parsers { 

    type Elem = Char 

    def notComma = elem("not comma", _ != ',') 

    def notEndLine = elem("not end line", x => x != '\r' && x != '\n') 

    def text = rep(notComma | notEndLine) 

} 

object CombinatorParserTest { 

    def main(args:Array[String]): Unit = { 
    val p = new CombinatorParserTest() 
    val r = p.text(new CharSequenceReader(",")) 
    // does not get here 
    println(r) 
    } 

} 

Làm cách nào tôi có thể in những gì đang diễn ra? Và tại sao điều này không kết thúc?

Trả lời

4

Ghi nhật ký các nỗ lực phân tích cú pháp notCommanotEndLine cho biết đó là phần cuối tệp (được hiển thị dưới dạng CTRL-Z trong đầu ra nhật ký (...) ("mesg")). Đây là cách tôi sửa đổi phân tích cú pháp của bạn cho mục đích này:

def text = rep(log(notComma)("notComma") | log(notEndLine)("notEndLine")) 

Tôi không hoàn toàn chắc chắn những gì đang xảy ra (Tôi đã thử nhiều biến thể về ngữ pháp của bạn), nhưng tôi nghĩ đó là một cái gì đó như thế này: Các EOF không phải là thực sự là một nhân vật được giới thiệu một cách nhân tạo vào luồng đầu vào, mà là một loại tình trạng vĩnh viễn ở cuối đầu vào. Do đó, ký tự giả EOF không bao giờ được tiêu thụ này được phân tích liên tục thành "không phải là dấu phẩy hoặc không phải là kết thúc dòng".

+0

Tôi nghĩ rằng EOF được giới thiệu nhân tạo, nhưng bạn nói đúng khi nói rằng nó được liên tục phân tích vào nó dường như liên tục được cung cấp khi yêu cầu một ký tự bổ sung khi đầu vào đã ở cuối chuỗi. – huynhjl

2

Ok, tôi nghĩ tôi đã tìm ra điều này. `CharSequenceReader trả về '\ 032' làm điểm đánh dấu cho phần cuối của đầu vào. Vì vậy, nếu tôi sửa đổi đầu vào của tôi như thế này, nó hoạt động:

import util.parsing.combinator.Parsers 
import util.parsing.input.CharSequenceReader 

class CombinatorParserTest extends Parsers { 

    type Elem = Char 

    import CharSequenceReader.EofCh 

    def notComma = elem("not comma", x => x != ',' && x!=EofCh) 

    def notEndLine = elem("not end line", x => x != '\r' && x != '\n' && x!=EofCh) 

    //def text = rep(notComma | notEndLine) 
    def text = rep(log(notComma)("notComma") | log(notEndLine)("notEndLine")) 

} 

object CombinatorParserTest { 

    def main(args:Array[String]): Unit = { 
    val p = new CombinatorParserTest() 
    val r = p.text(new CharSequenceReader(",")) 
    println(r) 
    } 

} 

Xem mã nguồn cho CharSequenceReaderhere. Nếu số scaladoc đã đề cập đến nó, nó sẽ giúp tôi tiết kiệm rất nhiều thời gian.

+1

Tìm hiểu xem nó nên được đề cập ở đâu và mở một vé doc. Nếu bạn có thể cung cấp một bản vá với scaladoc đã sửa đổi, thì càng nhiều càng tốt. –

+0

Đã gửi https://lampsvn.epfl.ch/trac/scala/ticket/3147. Có nhiều tập tin bằng cách sử dụng 'EofCh', vì vậy tôi không chắc chắn nơi tốt nhất là nơi. – huynhjl

0

Tôi thấy chức năng ghi nhật ký cực kỳ khó xử khi nhập. Giống như tại sao tôi phải làm log(parser)("string")? Tại sao không có cái gì đơn giản như parser.log("string")? Dù sao, để khắc phục điều đó, tôi thực hiện điều này thay vì:

trait Logging { self: Parsers => 

    // Used to turn logging on or off 
    val debug: Boolean 

    // Much easier than having to wrap a parser with a log function and type a message 
    // i.e. log(someParser)("Message") vs someParser.log("Message") 
    implicit class Logged[+A](parser: Parser[A]) { 
     def log(msg: String): Parser[A] = 
      if (debug) self.log(parser)(msg) else parser 
    } 
} 

Bây giờ trong phân tích cú pháp của bạn, bạn có thể trộn trong đặc điểm này như sau:

import scala.util.parsing.combinator.Parsers 
import scala.util.parsing.input.CharSequenceReader 


object CombinatorParserTest extends App with Parsers with Logging { 

    type Elem = Char 

    override val debug: Boolean = true 

    def notComma: Parser[Char] = elem("not comma", _ != ',') 
    def notEndLine: Parser[Char] = elem("not end line", x => x != '\r' && x != '\n') 
    def text: Parser[List[Char]] = rep(notComma.log("notComma") | notEndLine.log("notEndLine")) 

    val r = text(new CharSequenceReader(",")) 

    println(r) 
} 

Bạn cũng có thể ghi đè lên các lĩnh vực debug để tắt đăng nhập nếu muốn.

Chạy này cũng cho thấy sự phân tích cú pháp thứ hai phân tích một cách chính xác các dấu phẩy:

trying notComma at [email protected] 
notComma --> [1.1] failure: not comma expected 

, 
^ 
trying notEndLine at [email protected] 
notEndLine --> [1.2] parsed: , 
trying notComma at [email protected] 
notComma --> [1.2] failure: end of input 

, 
^ 
trying notEndLine at [email protected] 
notEndLine --> [1.2] failure: end of input 

, 
^ 
The result is List(,) 

Process finished with exit code 0 
Các vấn đề liên quan