2010-04-16 5 views
15

Cho một nhóm các đối tượng thực hiện các trình kết hợp phân tích cú pháp, làm cách nào để kết hợp các trình phân tích cú pháp? Vì Parsers.Parser là một lớp bên trong và trong Scala inner classes are bound to the outer object, câu chuyện trở nên hơi phức tạp.Scala: Làm thế nào để kết hợp các trình kết hợp phân tích cú pháp từ các đối tượng khác nhau

Dưới đây là ví dụ cố gắng kết hợp hai trình phân tích cú pháp từ các đối tượng khác nhau.

import scala.util.parsing.combinator._ 

class BinaryParser extends JavaTokenParsers { 
    def anyrep: Parser[Any] = rep(any) 
    def any: Parser[Any] = zero | one 
    def zero: Parser[Any] = "0" 
    def one: Parser[Any] = "1" 
} 

object LongChainParser extends BinaryParser { 
    def parser1: Parser[Any] = zero~zero~one~one 
} 

object ShortChainParser extends BinaryParser { 
    def parser2: Parser[Any] = zero~zero 
} 

object ExampleParser extends BinaryParser { 
    def parser: Parser[Any] = (LongChainParser.parser1 
    ||| ShortChainParser.parser2) ~ anyrep 

    def main(args: Array[String]) { 
    println(parseAll(parser, args(0))) 
    } 
} 

Điều này dẫn đến các lỗi sau:

<console>:11: error: type mismatch; 
found : ShortChainParser.Parser[Any] 
required: LongChainParser.Parser[?] 
     def parser: Parser[Any] = (LongChainParser.parser1 
      ||| ShortChainParser.parser2) ~ anyrep 

tôi đã tìm thấy giải pháp cho vấn đề này đã có, nhưng kể từ khi nó được đưa lên gần đây trên scala người dùng ML (Problem injecting one parser into another), đó là có lẽ cũng đáng để đặt nó ở đây.

Trả lời

17

Câu trả lời nhanh chóng là sử dụng trait s thay vì lưu trữ các phân tích cú pháp trong object s:

import scala.util.parsing.combinator._ 

trait BinaryParser extends JavaTokenParsers { 
    def anyrep: Parser[Any] = rep(any) 
    def any: Parser[Any] = zero | one 
    def zero: Parser[Any] = "0" 
    def one: Parser[Any] = "1" 
} 

trait LongChainParser extends BinaryParser { 
    def parser1: Parser[Any] = zero~zero~one~one 
} 

trait ShortChainParser extends BinaryParser { 
    def parser2: Parser[Any] = zero~zero 
} 

object ExampleParser extends LongChainParser with ShortChainParser { 
    def parser: Parser[Any] = (parser1 ||| parser2) ~ anyrep 

    def main(args: Array[String]) { 
    println(parseAll(parser, args(0))) 
    } 
} 

Bởi vì các nhà khai thác combinator như ~| được viết so với lớp bên trong, leo thang các tài liệu tham khảo phân tích cú pháp để lớp - bằng cách nói BinaryParser#Parser[_] không làm bạn tốt. Việc sử dụng các đặc điểm giải quyết tất cả các vấn đề trong lớp kể từ khi cả hai Parser[Any] từ LongChainParserShortChainParser giờ đây tham chiếu đến lớp bên trong của đối tượng ExampleParser.

+1

Cảm ơn bạn đã đăng câu hỏi này và tất nhiên là để trả lời câu hỏi đó! Điều này thật đúng với gì mà tôi đã tìm kiếm. –