Bạn đang đi đúng hướng. Có một vài vấn đề trong trình phân tích cú pháp của bạn. Tôi sẽ đăng mã đã sửa, sau đó giải thích các thay đổi.
import scala.util.parsing.combinator._
import scala.util.parsing.combinator.syntactical._
case class Book (name: String, isbn: String) {
def niceName = name + " : " + isbn
}
object BookParser extends StandardTokenParsers {
lexical.reserved += ("book","has","isbn")
def bookSpec: Parser[Book] = "book" ~ ident ~ "has" ~ "isbn" ~ ident ^^ {
case "book" ~ name ~ "has" ~ "isbn" ~ isbn => new Book(name, isbn) }
def parse (s: String) = {
val tokens = new lexical.Scanner(s)
phrase(bookSpec)(tokens)
}
def test (exprString : String) = {
parse (exprString) match {
case Success(book, _) => println("Book: " + book.niceName)
case Failure(msg, _) => println("Failure: " + msg)
case Error(msg, _) => println("Error: " + msg)
}
}
def main (args: Array[String]) = {
test ("book ABC has isbn DEF")
}
}
1. giá trị Parser trở
Để trả về một cuốn sách từ một phân tích cú pháp, bạn cần phải cung cấp cho các loại inferencer một số giúp đỡ. Tôi đã thay đổi định nghĩa của hàm bookSpec thành rõ ràng: nó trả về một Trình phân tích cú pháp [Sách]. Nghĩa là, nó trả về một đối tượng là một trình phân tích cú pháp cho sách.
2. stringLit
Chức năng stringLit bạn sử dụng xuất phát từ đặc điểm StdTokenParsers. stringLit là một hàm trả về Parser [String], nhưng mẫu nó khớp với các dấu ngoặc kép mà hầu hết các ngôn ngữ sử dụng để phân định một chuỗi ký tự. Nếu bạn hài lòng với các từ kép trong DSL của bạn, thì stringLit là những gì bạn muốn. Vì lợi ích của sự đơn giản, tôi đã thay thế stringLit bằng ident. ident tìm kiếm một mã nhận dạng ngôn ngữ Java. Đây không thực sự là định dạng phù hợp cho ISBN, nhưng nó đã vượt qua trường hợp thử nghiệm của bạn. :-)
Để khớp chính xác ISBN, tôi nghĩ bạn sẽ cần phải sử dụng cụm từ regex thay vì idents.
3. Bỏ qua bên trái chuỗi
khớp của bạn sử dụng một chuỗi các ~> và tổ hợp. Đây là một hàm nhận hai đối tượng Parser [_] và trả về một Trình phân tích cú pháp nhận dạng cả hai theo thứ tự, sau đó trả về kết quả của phía bên tay phải. Bằng cách sử dụng một chuỗi toàn bộ chúng để dẫn đến chuỗi cuối cùng của bạn, trình phân tích cú pháp của bạn sẽ bỏ qua mọi thứ ngoại trừ từ cuối cùng trong câu. Điều đó có nghĩa là nó sẽ vứt bỏ tên sách.
Ngoài ra, khi bạn sử dụng ~> hoặc < ~, các mã thông báo bị bỏ qua sẽ không xuất hiện trong kết hợp mẫu của bạn.
Để đơn giản, tôi đã thay đổi tất cả thành các hàm chuỗi đơn giản và để lại các mã thông báo bổ sung trong khớp mẫu.
4. Kết hợp kết quả
Phương pháp kiểm tra cần phải phù hợp với tất cả các kết quả có thể từ parse() chức năng. Vì vậy, tôi đã thêm các trường hợp Thất bại() và Lỗi().Ngoài ra, ngay cả Thành công cũng bao gồm cả hai giá trị trả về của bạn và đối tượng Reader. Chúng tôi không quan tâm đến người đọc, vì vậy tôi chỉ sử dụng "_" để bỏ qua nó trong khớp mẫu.
Hy vọng điều này sẽ hữu ích!
xuất sắc trả lời cảm ơn bạn - đã trải qua tất cả các sách Scala hiện tại và sắp tới, và đây là một câu trả lời tốt hơn so với hai Tôi có đối phó với nó (Martin Odersky của cũng như một đến từ Wampler & Payne) – ShaunL