2011-02-08 26 views
8

vì vậy tôi có một cái gì đó như thế này:làm thế nào để làm cho scala phân tích cú pháp không

class MyParser extends JavaTokenParsers { 
    var m = new HashMap[String,String] 
    def store = ("var" ~> ident "=") ~ ident ^^ { 
     case k ~ v => m += k -> v 
    } 
    def stored_val = ident ^^ { 
     case k => m(k) 
    } 
} 

Và vấn đề của tôi được rằng những gì tôi thực sự muốn làm là có phân tích cú pháp stored_val thất bại để phân tích cú pháp khác có cơ hội để phù hợp với đầu vào. Nhưng những gì xảy ra bây giờ là bản đồ ném khi nó không thể tìm thấy giá trị.

tôi đã cố gắng thực hiện stored_val như thế này:

def stored_val = ident => { 
    case k => if (m.contains(k)) m(k) else failure("identifier not found") 
} 

Nhưng vấn đề với điều đó là sự thất bại trả Parser [Không có gì] mà là một loại khác với String.

+1

Tôi có cùng một vấn đề chính xác và muốn xóa trình phân tích cú pháp một cách rõ ràng. Làm thế nào là thất bại nghĩa vụ phải được sử dụng nếu loại không có gì của nó là không tương thích với bất cứ điều gì? – hotzen

Trả lời

3

Nếu bạn muốn kiểm tra nội dung của các ký tự ngoài regex, bạn có thể muốn xem StandardTokenParser. Đặc biệt,

def elem (kind: String, p: (Elem) ⇒ Boolean) : Parser[Elem] 

Một phân tích cú pháp phù hợp với các yếu tố đầu vào đáp ứng một vị trao elem(kind, p) thành công nếu đầu vào bắt đầu với một yếu tố e'p(e) là đúng.

Sửa: Đối với ví dụ về các tiêu chuẩn Mã Parser, kiểm tra bài viết Jim McBeath về Scala Parser Combinators. Tôi đã sửa đổi nhanh ví dụ đầu tiên để minh họa elem. Đó là một phân tích cú pháp đơn giản mà chỉ mất tổng của số lẻ:

import scala.util.parsing.combinator.syntactical._ 
import scala.util.parsing.combinator._ 

trait Expression 
case class EConstant(value: Int) extends Expression 
case class EAdd(lhs: Expression, rhs: Expression) extends Expression 

object ExpressionParser extends StandardTokenParsers { 
    lexical.delimiters ++= List("+") 

    def oddValue = elem("odd", { x => x.toString.toInt % 2 == 1 }) ^^ { 
    x => EConstant(x.toString.toInt) } 
    def value = numericLit ^^ { x => EConstant(x.toInt) } 

    def sum = oddValue ~ "+" ~ oddValue ^^ { case left ~ "+" ~ right => 
      EAdd(left, right) } 

    def expr = (sum | value) 

    def parse(s:String) = { 
    val tokens = new lexical.Scanner(s) 
    phrase(expr)(tokens) 
    } 

    def apply(s:String): Expression = parse(s) match { 
    case Success(tree, _) => tree 
    case e: NoSuccess => 
     throw new IllegalArgumentException("Bad syntax: "+s) 
    } 
} 

Save the trên như ExpressionParser.scala và tải nó vào REPL như sau:

scala> :l ExpressionParser.scala  
Loading ExpressionParser.scala... 
import scala.util.parsing.combinator.syntactical._ 
import scala.util.parsing.combinator._ 
defined trait Expression 
defined class EConstant 
defined class EAdd 
defined module ExpressionParser 

scala> ExpressionParser("2 + 2") 
java.lang.IllegalArgumentException: Bad syntax: 2 + 2 
    at ExpressionParser$.apply(<console>:42) 
    at .<init>(<console>:24) 
    at .<clinit>(<console>) 
    at RequestResult$.<init>(<console>:9) 
    at RequestResult$.<clinit>(<console>) 
    at RequestResult$scala_repl_result(<console>) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988) 
    at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988) 
    at scala.util.con... 
scala> ExpressionParser("1 + 1") 
res3: Expression = EAdd(EConstant(1),EConstant(1)) 
+0

@Kevin nói - Tôi đã thấy phương pháp đó, nhưng tôi đã không chắc chắn chính xác cách sử dụng nó. Bạn có thể cung cấp một ví dụ nhỏ không? Về cơ bản tôi muốn vị từ của tôi trả về true nếu m.contains (k) == true. – jjnguy

+0

Tôi đã thấy phương pháp đó, nhưng tôi đã không chính xác chắc chắn làm thế nào để sử dụng nó. Bạn có thể cung cấp một ví dụ nhỏ không? Về cơ bản tôi muốn vị từ của tôi trả về true nếu m.contains (k) == true. –

8

Bạn có thể sử dụng combinator ^? mà chấp nhận một chức năng một phần (Scaladoc):

def stored_val: Parser[String] = ident ^? { 
    case k if m.contains(k) => m(k) 
} 

tôi đẩy một full example với tests để Github.

Các vấn đề liên quan