9

Im viết trình biên dịch cho dự án đại học và tôi muốn chuyển đổi Abstract Syntax Tree thành Biểu đồ luồng điều khiển (CFG).Xây dựng chính thức Biểu đồ luồng điều khiển

Tôi nghĩ rằng các nút (V) trong CFG phải là các nút từ AST. Tôi biết thuật toán làm thế nào để xây dựng tập cạnh (G=(V,E)) nhưng Im có một thời gian khó viết quá trình này một chút chính thức hơn

tôi đã tạo ra này hoa văn phong cách phù hợp với scala (Pseudo):

def edges(n:Node)(nestedin_next: Node) : List[(Node,Node)] = 
    n match { 
     case (c_1 :: c_2::tl) => (c1,c2) :: edges(c2::tl)(nestedin_next)++ 
            edges(c_1)(c_2)//recurse 
     case c_1 :: Nil => (c_1,nestedin_next)::Nil 
     case [email protected] IF(_,c1,c2) => (i,c1)::(i,c2)::edges(c1)(nestedin_next)++ 
           edges(c2)(nestedin_next) 
     case _ => Nil 
    } 

nào phải phù hợp với một cấu trúc AST như:

(IF(1, 
     ASSIGN(x,1), // ia1 
     ASSIGN(x,2) // ia2 
    ) :: // i1 
    ASSIGN(y,2) :: // a1 
    ASSIGN(z,ADD(x,y)) :: //a2 
    IF(z, 
     RET(z), //i2r1 
     assign(z,0):: // i2a1 
     ret(z) // i2r2 
) :://i2 
    Nil 
) 

và cung cấp một edgeset như:

{ i1 -> ia1, 
    i1 -> ia2, 
    ia1 -> a1, 
    ia2 -> a1, 
    a1 -> a2, 
    a2 -> i2, 
    i2 -> i2r1 
    i2-> i2a1 
    i2a1 -> i2r2 
    i2r2 -> _|_ 
    i2r1 -> _|_ 
} 

CFG(dot) DotSrc

Bất cứ ai có bất kỳ gợi ý về cách để làm điều này một chút chính thức hơn scala "giả"?

Im suy nghĩ một cái gì đó quy nạp như:

e[[ IF(_,b1,b2) ]] = (if -> b1) + (if -> b2) \cup e[[ b1 ]] \cup e[[ b2 ]] 
e[[ b1, b2 ]] = e[[b1]] \cup e[[b2]] 

(ở trên sẽ chỉ cung cấp cho một cái cây và không phải là một đồ thị mặc dù Không cạnh từ mép sau đó ngành để tuyên bố tiếp theo ví dụ.)

EDIT :

Tôi đã đọc lên trên kiama and dataflows cho scala và tôi thích phương pháp "succ" và "theo dõi" mà họ sử dụng. Tuy nhiên, tôi đang gặp khó khăn trong việc đun sôi nó thành một mô tả chính thức hơn, chủ yếu là bởi vì các số childAttr, s.next tiện lợi, ẩn một số chi tiết biến xấu xí khi tôi cố gắng chỉ định nó một cách chính thức.

EDIT2:

Tôi đã trải qua Sách Dragon và "Modern Compiler Thực hiện trong ML" cũng như một số các vật chất khác từ Learning to write a compiler và một số/đề cập đến hầu hết các luồng dữ liệu và kiểm soát dòng chảy, nhưng không bao giờ chạm nhiều khi LÀM THẾ NÀO để tạo CFG theo bất kỳ cách thức chính thức nào.

EDIT3:

Via Kiama tác giả, Associate Professor Dr. Tony Sloane tôi nhận được một số additional book references to look up.

Theo tôi có thể thấy "cách thực hiện" theo những sách đó dựa trên "mỗi câu lệnh" của chương trình nhiều hơn AST và dựa trên các khối cơ bản. Tuy nhiên, đầu vào tuyệt vời!

+0

Tôi hy vọng bạn không nhớ rằng tôi đã thêm "scala" vào thẻ. –

+0

@Randall Không phải tất cả :) Tôi gần như đã làm như vậy tự của tôi – svrist

Trả lời

3

Nếu ý định của bạn chỉ đơn giản là tạo ra một cái gì đó có vẻ trang trọng hơn một chút, thì bạn có thể diễn tả các hoạt động phù hợp này dưới dạng quy tắc suy luận bằng cách sử dụng standard notation. Bạn nên thể hiện nó chỉ bằng một bước giảm, chứ không phải đệ quy, bởi vì thế là đủ để đơn giản tiếp tục áp dụng những quy tắc này cho đến khi không còn có thể áp dụng được nữa.

Điều đó nói rằng, định nghĩa này về cơ bản sẽ nói chính xác điều tương tự như mã scala của bạn.Nếu bạn thực sự muốn làm bất cứ điều gì "chính thức" các thuộc tính bạn cần phải chứng minh là:

  • thuật toán dịch CFG của bạn luôn luôn kết thúc
  • Dù CFG của bạn là tối thiểu đối với một AST đầu vào cho
  • Cho dù có là một CFG duy nhất có thể phát sinh bởi thuật toán của bạn cho một đầu vào AST đã cho (nghĩa là nó không phải là không xác định được CFG mà nó tạo ra).

Tôi không nghĩ rằng phương pháp tiếp cận khối cơ bản của bạn (thay vì cách tiếp cận theo từng câu lệnh) cũng nhất thiết là một ý tưởng tồi. Dường như hoàn toàn hợp lý rằng nếu bạn có thể khớp một khối cơ bản, bạn có thể viết một quy tắc xác nhận về tư cách thành viên được đặt dựa trên sự hiện diện của trận đấu này. Có vẻ như định nghĩa quy nạp bạn bắt đầu vẽ có thể hoạt động tốt.

Điều gì đó thú vị khác có thể là cố gắng liên hệ (chính thức) structured operational semantics và việc xây dựng CFG của bạn. Có thể đã có công việc trong lĩnh vực này, nhưng tôi chỉ thực hiện một tìm kiếm google nguyền rủa và không tìm thấy bất kỳ mối quan hệ rõ ràng đã nêu giữa hai, nhưng trực giác có vẻ như một nên tồn tại.

+0

Đầu vào rất tốt! Liên quan đến ngữ nghĩa hoạt động (và các quy tắc suy luận), gần đây họ đã suy nghĩ rất nhiều về tôi, vì vậy điều thú vị là bạn đề cập đến nó. – svrist

4

Google's Closure Compiler triển khai Control-Flow Analysis biến đổi AST cho JavaScript thành Biểu đồ kiểm soát luồng. Ý tưởng cho việc triển khai này được lấy cảm hứng từ bài báo: Declarative Intraprocedural Flow Analysis of Java Source Code.

+0

Aha! Kiama dựa trên JastAdd, và bài báo này sử dụng JastAdd. Các ví dụ dataflow của Kiama trông rất liên quan đến cách tiếp cận được sử dụng trong bài báo. Cảm ơn – svrist

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