2015-02-05 6 views
2

я написал следующее привет-мира parboiled2 парсер:Как заставить parboiled2 соответствовать всему вводу?

class MyParser(val input: ParserInput) extends Parser { 

/* 
    Expr  <- Sum 
    Sum  <- Product ('+') Product)* 
    Product <- Value (('*') Value)* 
    Value <- Constant | '(' Expr ')' 
    Constant <- [0-9]+ 
    */ 

    def Expr: Rule1[Int] = rule { Sum } 

    def Sum: Rule1[Int] = rule { oneOrMore(Product).separatedBy(" + ") ~> ((products: Seq[Int]) => products.sum) } 

    def Product: Rule1[Int] = rule { oneOrMore(Value).separatedBy(" * ") ~> ((values: Seq[Int]) => values.product) } 

    def Value: Rule1[Int] = rule { Constant | ('(' ~ Expr ~ ')') } 

    def Constant: Rule1[Int] = rule { capture(oneOrMore(Digit)) ~> ((digits: String) => digits.toInt) } 

} 

Это работает в основном, как и ожидалось, например он успешно анализирует «1 + 2» как 3.

Если я даю ему недопустимый ввод, такой как «1 + (2», я ожидал бы, что синтаксический анализ завершится неудачно, но на самом деле он преуспевает, в результате чего результат равен 1.

Похоже, что parboiled2 анализирует только часть ввода и игнорирует оставшуюся часть, которую он не может проанализировать. Является ли это ожидаемым поведением? Есть ли способ заставить синтаксический анализатор проанализировать весь ввод и сбой, если он не может этого сделать?

ответ

3

Это ожидаемое поведение. parboiled2 является парсер PEG, и, как описано в разделе в документации Common Mistakes, она ест все, что можно найти.

Чтобы избежать такой проблемы, убедитесь, что вы ожидаете символ конца входного текста в конце вашей строки:

def Expr: Rule1[Int] = rule { Sum ~ EOI } 
+0

Спасибо, добавив '~ EOI' к корневому правилу является хорошим, простым решением. На самом деле я не мог найти это в README, и это похоже на проблему, с которой сталкиваются многие новички, поэтому я отправлю PR, чтобы добавить ее. –

1

Если я ввода «1+ (2 + 3 * 4) +5» , анализ не завершится. Определяет другой корень правило и оставляет Expr как это было будет делать трюк:

def InputLine = rule { Expr ~ EOI } 
def Expr: Rule1[Int] = rule { Sum }