2017-01-17 3 views
0

Ich versuche Parser Kombinatoren mit Scala zu verstehen, und haben folgendes geschrieben:Wie bekomme ich diesen einfachen Regex-Parser, um einen Booleschen Ausdruck abzufangen?

import scala.util.parsing.combinator._ 

class SimpleParser extends RegexParsers { 

    def operand: Parser[String] = "[A-Za-z]+".r ^^ {_.toString} 

    def operator: Parser[String] = "OR|AND".r ^^ {_.toString} 

    def term: Parser[String] = (("(" ~> (operand ~ operator ~ operand) <~ ")")) ^^ { 
    case o1 ~ operator ~ o2 => o1 + " " + operator + " " + o2 
    case _ => " " 
    } 


    def expression: Parser[String] = (operand | term | (operand ~ operator ~ term))^^ { 
    case str:String => str 
    case operand ~ operator ~ term => operand + " " + operator + " " + term 
    } 
} 

object ParserTest extends SimpleParser{ 
    def main(args: Array[String]): Unit = { 
    println(parseAll(expression, "A").get) 
    println(parseAll(expression, "(A OR C)").get) 
    println(parseAll(expression, "A AND (A OR C)").get) 
    } 
} 

Die ersten beiden Drucke Werke zu finden, während die letzte Ursachen:

Exception in thread "main" java.lang.RuntimeException: No result when parsing failed at scala.sys.package$.error(package.scala:27) 
at scala.util.parsing.combinator.Parsers$NoSuccess.get(Parsers.scala:181) 
at scala.util.parsing.combinator.Parsers$NoSuccess.get(Parsers.scala:167) 
at ParserTest$.main(ParserTest.scala:31) 
at ParserTest.main(ParserTest.scala) 

dachte ich den letzten Satz würde das Muster (Operand ~ Operator ~ Begriff) in "Ausdruck" übereinstimmen. Kann mir jemand erklären, warum mein Muster falsch ist, und vielleicht den Schreibvorgang so zeigen, dass er mit der letzten Druckanweisung übereinstimmt?

Antwort

2

Zuerst behandeln Sie das Ergebnis von parseAll nicht richtig. Wenn Sie sind, würden Sie, dass am letzten Beispiel sehen, wurde

[1.3] failure: end of input expected 

A AND (B OR C) 
^

Das Problem ist hier ein Failure mit der Nachricht zurückkehr Sie Ihre Parser innerhalb expression in der falschen Reihenfolge haben.

Wenn Sie eine Disjunktion von Parsern erstellen (uisng |), müssen Sie immer mit dem "gierigsten" Parser beginnen. Mit anderen Worten, was hier passiert, ist, dass operand an sich das Parsen des "A" und das Parsen erfolgreich ist. parseAll sieht jedoch, dass das Parsing zwar erfolgreich war, aber immer noch Eingaben übrig sind, sodass der obige Fehler zurückgegeben wird.

Wenn Sie die Reihenfolge der 3-Parser umzukehren, so dass es wie folgt aussieht:

def expression: Parser[String] = ((operand ~ operator ~ term) | term | operand)^^ 

sie jetzt richtig geordnet und alle drei Beispiele arbeiten.

+0

Vielen Dank. Ich habe das nicht als Problem betrachtet. – stian

Verwandte Themen