Jesteś na dobrej drodze. W twoim parserze jest kilka problemów. Opublikuję poprawiony kod, a następnie wytłumaczę zmiany.
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. Wartość zwracana Parser
W celu powrotu książkę z parsera, trzeba podać typ inferencer pomoc. Zmieniłem definicję funkcji bookSpec tak, aby była jawna: zwraca Parser [Book]. Oznacza to, że zwraca obiekt, który jest analizatorem składni dla książek.
2. stringLit
Funkcja stringLit użyłeś pochodzi z cechą StdTokenParsers. stringLit to funkcja, która zwraca Parser [String], ale dopasowany wzorzec zawiera podwójne cudzysłowy, których większość języków używa do ograniczania literału łańcuchowego. Jeśli jesteś zadowolony z podwójnego cytowania słów w twoim DSL, wtedy stringLit jest tym, czego potrzebujesz. Dla uproszczenia zastąpiłem stringLit identyfikatorem. Ident wyszukuje identyfikator w języku Java. Nie jest to właściwy format dla numerów ISBN, ale minął test. :-)
Aby poprawnie dopasować numery ISBN, myślę, że będziesz potrzebować użyć wyrażenia regularnego zamiast identyfikatora.
3. ignorowanych lewo sekwencja
Twój dopasowujący używany ciąg ~> sumatory. Jest to funkcja, która pobiera dwa obiekty Parser [_] i zwraca Parser, który rozpoznaje oba w kolejności, a następnie zwraca wynik po prawej stronie. Używając całego łańcucha, który doprowadzi do ostatecznego stringLit, twój parser zignorowałby wszystko oprócz ostatniego słowa w zdaniu. Oznacza to, że wyrzuci też nazwę książki.
Również, gdy używasz ~> lub < ~, ignorowane tokeny nie powinny pojawiać się w dopasowaniu do wzorca.
Dla uproszczenia zmieniłem te wszystkie na proste funkcje sekwencyjne i pozostawiłem dodatkowe żetony w dopasowaniu wzorca.
4. Dalsze wyniki
Metoda badawcza musi pasować do wszystkich możliwych wynika z funkcji() przetworzenia. Dodałem więc przypadki Failure() i Error().Ponadto, nawet Sukces zawiera zarówno swoje wartości zwracanej i obiekt Reader. Nie interesuje nas czytelnik, więc użyłem "_", aby zignorować go w dopasowaniu wzorca.
Mam nadzieję, że to pomoże!
Doskonała odpowiedź dziękuję - zostały przechodząc przez wszystkich obecnych i przyszłych książek Scala, i jest to lepsze rozwiązanie niż dwa mam który sobie z tym poradzić (Martin Odersky, jak również tego, pochodzących z Wampler & Payne) – ShaunL