2009-02-08 27 views
11

Tôi có EBNF sau mà tôi muốn phân tích:EBNF để Scala phân tích cú pháp combinator

PostfixExp  -> PrimaryExp ("[" Exp "]" 
           | . id "(" ExpList ")" 
           | . length)* 

Và đây là những gì tôi nhận:

def postfixExp: Parser[Expression] = (
    primaryExp ~ rep(
     "[" ~ expression ~ "]" 
     | "." ~ ident ~"(" ~ repsep(expression, ",") ~ ")" 
     | "." ~ "length") ^^ { 
     case primary ~ list => list.foldLeft(primary)((prim,post) => 
       post match { 
        case "[" ~ length ~ "]" => ElementExpression(prim, length.asInstanceOf[Expression]) 
        case "." ~ function ~"(" ~ arguments ~ ")" => CallMethodExpression(prim, function.asInstanceOf[String], arguments.asInstanceOf[List[Expression]]) 
        case _ => LengthExpression(prim) 
       } 
      ) 
    }) 

Nhưng tôi muốn biết nếu có một cách tốt hơn, tốt nhất là không cần phải sử dụng để đúc (asInstanceOf).

Trả lời

12

tôi sẽ làm điều đó như thế này:

type E = Expression 

def postfixExp = primaryExp ~ rep(
    "[" ~> expr <~ "]" ^^ { e => ElementExpression(_:E, e) } 
    | "." ~ "length" ^^^ LengthExpression 
    | "." ~> ident ~ ("(" ~> repsep(expr, ",") <~ ")") ^^ flatten2 { (f, args) => 
     CallMethodExpression(_:E, f, args) 
    } 
) ^^ flatten2 { (e, ls) => collapse(ls)(e) } 

def expr: Parser[E] = ... 

def collapse(ls: List[E=>E])(e: E) = { 
    ls.foldLeft(e) { (e, f) => f(e) } 
} 

rút gọn expressions-expr cho ngắn gọn cũng như bổ sung các loại bí danh E với lý do tương tự.

Bí quyết mà tôi đang sử dụng ở đây để tránh phân tích trường hợp xấu là trả lại giá trị hàm từ bên trong sản xuất bên trong. Hàm này có một số Expression (sẽ là primary) và sau đó trả về một số Expression mới dựa trên giá trị đầu tiên. Điều này hợp nhất hai trường hợp dấu chấm công và biểu thức được đặt ngoặc vuông. Cuối cùng, phương thức collapse được sử dụng để hợp nhất các giá trị hàm List tuyến tính vào một AST thích hợp, bắt đầu với biểu thức chính được chỉ định.

Lưu ý rằng LengthExpression chỉ được trả về dưới dạng giá trị (sử dụng ^^^) từ sản xuất tương ứng. Điều này làm việc vì các đối tượng đồng hành cho các lớp chữ hoa (giả sử rằng LengthExpression thực sự là một kiểu chữ) mở rộng giá trị hàm tương ứng ủy nhiệm cho hàm tạo của chúng. Do đó, hàm được đại diện bởi LengthExpression mất một đơn Expression và trả về phiên bản mới LengthExpression, đáp ứng chính xác nhu cầu của chúng tôi về việc xây dựng cây bậc cao hơn.

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