2014-01-24 11 views
5

Ich habe Mühe zu verstehen, wie der Scala Parser Kombinator API verwendet werden soll, wenn Sie bereits eine Liste von Token (die keine Zeichen sind). Ich habe mir den Quellcode für TokenParsers angesehen, aber ich verstehe nicht, was das "lexikalische" Mitglied ist und wie ich meine eigene Reader-Implementierung (oder eine andere Art, wie meine Token vom Parser konsumiert werden können) pluginieren kann.Verbinden eines benutzerdefinierten Tokenizers mit einer Unterklasse Parser

Die online verfügbaren Beispiele (und in dem Buch "Programming in Scala" von Odersky et al.) Zeigen nicht, wie man die API mit Nicht-Charakter-Token verwendet. Einige Beispiele zeigen, dass eine Unterklasse von Parsers den elem-Parameter auf den Token-Typ setzen muss, aber , wobei die Tokens sind, die von kommen? Wo ist der Eingabeparameter Reader [MyToken]?

Nur um zu verdeutlichen: Die lexikalische Analyse ist bereits erfolgt. Whitespace-Entfernung, Delimiter, all das ist erledigt. Ich habe eine Liste von Token und möchte nur die Paranumer-Kombinator-Niceeness verwenden, um einen AST zu erstellen. Die Token schauen etwas wie folgt aus:

sealed abstract class MyToken { 
    val line : Int 
    val col : Int 
} 
case class LPAREN (line : Int, col : Int) extends MyToken 
case class RPAREN (line : Int, col : Int) extends MyToken 

Etc.

Antwort

3

Habe ich es schließlich aus. Die phrase() -Methode verwendet einen Reader-Parameter, sodass ich meinen Token-Stream umbrechen und ihn aufrufen kann.

class MyParsers extends Parsers { 
    type Elem = MyToken 

    def parse(tokens: Iterable[MyToken]): ParseResult[Any] = { 
    val reader = new MyReader(tokens) 
    phrase(myGrammarRule)(reader) 
    } 

    // ...etc... 
} 

sealed class MyReader(tokens : Iterable[MyToken]) extends Reader[MyToken] { 
    def pos : Position = tokens.head 
    def atEnd : Boolean = tokens.isEmpty 
    def rest : Reader[MyToken] = new MyReader(tokens.tail) 
    def first : MyToken = tokens.head 
} 

sealed abstract class MyToken extends Position { 
    val _line : Int 
    val _col : Int 

    override def column = _col 
    override def line = _line 
    override def lineContents = "" 
} 

case class LPAREN (_line : Int, _col : Int) extends MyToken 
case class RPAREN (_line : Int, _col : Int) extends MyToken 

Die Position mixin ist schön, weil es der Parser ermöglicht die bereits vorhandenen Positionsinformationen in meinem Token ohne zusätzliche Kleber zu verwenden.

+0

Hm, ich denke, wenn ich auch lineContents() implementieren werde ich schönere diagnostische Nachrichten vom Parser bekommen. – esl

+0

Danke für das schöne Beispiel. Ich habe selbst an einem benutzerdefinierten Token-Parser gehackt, aber Ihr Code ist sauberer :) – michael

Verwandte Themen