5 Thực nghiệm
2.34 Ví dụ so sánh mẫu
Chương 2.Kiến thức cơ bản
2.9 OCamllex và OCamlyacc
2.9.1 OCamllex
Ocamllex [15] là bộ sinh dùng để sinh ra chương trình phân tích đoán nhận các
mẫu từ vựng trong tập tin đầu vào. Các biểu thức chính quy và các luật được đặc tả trong tập tin từ vựng. Ocamllex sẽ sinh ra tập tin mã nguồn OCaml dựa vào tập tin đặc tả này. Tập tin mã nguồn được sinh ra sẽ định nghĩa các hàm xử lý từ vựng [15]. Tập tin mã nguồn được dịch và liên kết lại để sinh ra tập tin có khả năng thực thi. Tập tin thực thi này khi chạy sẽ xử lý đầu vào của nó dựa vào các biểu thức chính quy. Khi nó tìm thấy một từ vựng nó sẽ thực thi đoạn mã nguồn OCaml tương ứng. Tập tin mã nguồn đặc tả từ vựng có đuôi mở rộng là .mll. Để biên dịch tập tin này sử dụng dòng lệnh:ocamllex∗.mll. Tập tin đặc tả từ vựng gồm có bốn thành phần: header,các định nghĩa, các luậtvàtrailer. Trong đó, các thành phầnheadervàruleslà cần thiết còn hai thành phần còn lại làrules vàtrailerlà tùy chọn. Cấu trúc tập tin đặc tả từ vựng được mô tả như Hình 2.35. Hình 2.36 là ví dụ mô tả một tập tin đặc tả từ vựng.
(* thành phần header *) { header }
(* thành phần định nghĩa *) let ident = regexp
let ...
(* thành phần luật *)
rule entrypoint [arg1... argn] = parse | pattern { action }
| ...
| pattern { action }
and entrypoint [arg1... argn] = parse ... and ... (* thành phần trailer *) { trailer } Hình 2.35: Cấu trúc tập tin đặc tả từ vựng. 2.9.2 OCamlyacc
Ocamlyacc [16] là bộ sinh dùng để sinh ra chương trình phân tích cú pháp bằng
ngôn ngữ OCaml từ một tập tin đặc tả văn phạm phi ngữ cảnh. Chương trình OCaml này sẽ có chức năng phân tích cú pháp cho tập tin dữ liệu đầu vào tuân thủ theo văn phạm đó. Tập tin mã nguồn đặc tả cú pháp có đuôi mở rộng là .mly. Để biên dịch tập tin này sử dụng dòng lệnh:ocamlyacc∗.mly. Tập tin đặc
Chương 2.Kiến thức cơ bản { l e t num_lines = r e f 0 l e t num_chars = r e f 0 } r u l e count = parse
| '\n' { i n c r num_lines ; i n c r num_chars ; count ←-
l e x b u f } | _ { i n c r num_chars ; count l e x b u f } | e o f { ( ) } { l e t main ( ) = l e t l e x b u f = Lexing . from_channel s t d i n i n count l e x b u f ; P r i n t f . p r i n t f " # o f l i n e s = %d , # o f c h a r s = %d\n " !←- num_lines ! num_chars l e t _ = P r i n t e x c . p r i n t main ( ) } Hình 2.36: Ví dụ tập tin đặc tả từ vựng.
tả cú pháp gồm có bốn thành phần: header,khai báo Ocamlyacc, luật văn phạmvà trailer. Cấu trúc tập tin đặc tả cú pháp được mô tả như Hình 2.37.
%{
Header (mã nguồn OCaml) %}
Khai báo Ocamlyacc %%
Các luật văn phạm %%
trailer (có thể có mã nguồn OCaml)
Chương 3 AGTool
3.1 Giới thiệu AGTool
Phương pháp kiểm chứng mô hình còn gặp phải vấn đề "bùng nổ không gian trạng thái". Một giả thuyết được đặt ra là thay vì kiểm chứng trên toàn bộ hệ thống, chúng ta sẽ kiểm chứng từng thành phần của hệ thống đó. Với giả thuyết này thì phương pháp kiểm chứng giả định-đảm bảo có tiềm năng trong việc giải quyết bài toán của phương pháp kiểm chứng mô hình. Để sử dụng được phương pháp kiểm chứng đảm bảo giả định, chúng ta cần sinh ra cho hệ thống
một giả định (Assumption). Và AGTool [7] là một trong những công cụ dùng để
thực hiện công việc sinh ra giả định đó. Hình 3.1 mô tả tổng quan về AGTool.
Hình 3.1: Mô hình công cụ kiểm chứng AGTool.
Các thành phần M1, M2 và thuộc tính Pcủa hệ thống được đặc tả bởi các
Chương 3.AGTool
(a) LTS của các thành phần đầu vào.
(b) Tập tin đặc tả các thành phần đầu vào.
Hình 3.2: Thành phần đầu vào của AGTool.
dạng LTS. AGTool được cài đặt bằng ngôn ngữ lập trình hàm OCaml. Hiện tại, AGTool tương tác với người dùng bằng giao diện dòng lệnh. Các thành phần đầu vào được đưa vào từ tệp văn bản. Dưới đây là một ví dụ minh họa cho đầu vào và đầu ra của AGTool. Hình 3.2a mô tả các thành phần của hệ thống kênh truyền tin dưới dạng các biểu đồ trực quan. Đầu vào gồm có hai thành phần
M1, M2 của hệ thống và thuộc tính P. Các thành phần này được đặc tả bằng
dưới dạng biểu diễn liệt kê. Hình 3.2b minh họa tập tin chứa các đặc tả đầu vào. AGTool sinh ra giả định từ đặc tả ở Hình 3.2b. Hình 3.3 mô tả kết quả sinh ra bởi AGTool.
Chương 3.AGTool
3.2 Hạn chế của AGTool
Với các chức năng của AGTool hiện tại thì nó còn tồn tại một vài nhược điểm để có thể đưa vào ứng dụng trong thực tế. Kiểu dữ liệu đầu vào được biểu diễn dưới dạng liệt kê, công việc này yêu cầu người dùng phải chuẩn tập tin đầu vào một cách tỉ mỉ, mất nhiều thời gian và dễ gây lỗi. Không những vậy, với các biểu diễn đầu vào và đầu ra dưới dạng liệt kê thì AGTool không thể sử dụng lại các đặc tả của các công cụ kiểm chứng phần mềm khác như LTSA.
Chương 4
Chuyển đổi giữa các dạng biểu diễn của LTS
LTSA là một công cụ nổi tiếng về kiểm chứng phần mềm tương tranh [3]. AGTool
có thể giao tiếp được với LTSA có ý nghĩa quan trọng trong việc ứng dụng nó vào trong thực tế. Các thành phần trong dữ liệu đầu vào của công cụ LTSA được đặc tả bởi ngôn ngữ FSP. Trong khi đó, AGTool nhận dữ liệu đầu vào và sinh ra kết quả (giả định) ở LF. Để AGTool và LTSA có thể giao tiếp, sử dụng lại các kết quả của nhau thì đầu vào và đầu ra của hai công cụ này phải sử dụng chung một kiểu dữ liệu. Vì vậy, các thành phần đầu vào và kết quả của AGTool phải được đặc tả bởi ngôn ngữ FSP. Trong chương này, luận văn đưa ra phương pháp
giải quyết hai bài toán chính là: chuyển đổi FSP sang LF và chuyển đổi từ LF
sang FSP. Ý tưởng của phương pháp này là thiết kế hai thành phần có chức năng chuyển đổi qua lại giữa FSP và LF. Sau đó, các thành phần này được tích hợp vào công cụ AGTool. Hình 4.1 mô tả kiến trúc của GUI-AGTool. Trong đó, các thành phần mới sẽ được phát triển và tích hợp với AGTool Core.
Chương 4.Chuyển đổi giữa các dạng biểu diễn của LTS
4.1 Chuyển đổi FSP sang LF
4.1.1 Ý tưởng
Hệ thống sẽ cài đặt một thành phần riêng được gọi làFSP Compiler. Thành phần
này có chức năng chuyển đổi dữ liệu FSP sang LF. Bài toán chuyển đổi FSP sang LF được mô tả bởi Hình 4.2. Dữ liệu FSP ở đầu vào được xử lý bởi thành phần
Hình 4.2: Cấu trúc thành phần chuyển đổi từ FSP sang LF.
FSP Compiler. Các thành phần trong dữ liệu đầu vào sẽ được chuyển đổi từ danh sách các hàm chuyển trạng thái sang kiểu dữ liệu LF bởi Thuật toán 4.1.
Danh sách list_transitions gồm các phần tử có định dạng là (start_state, list_sub_trans). Trong đó, start_state là trạng thái ban đầu, list_sub_trans là danh sách các tiến trình con. Tiến trình con này được định nghĩa bởi một nhãn và một trạng thái kết thúc –stop_state. Tương ứng với mỗi tiến trình con, ta thu được một phần tử gồm ba thành phần: (start_state, label, stop_state). Phần tử này chính là một hàm chuyển trạng thái. Phần tử khởi tạo là trạng thái bắt đầu
của hàm dịch chuyển đầu tiên trong danh sách list_transitions. Danh sách các
trạng tháil_statesđược xác định tại các dòng 3, 4 và 8, 9 của thuật toán. Tại các bước này, một trạng thái xuất hiện sẽ được kiểm tra. Nếu trạng thái này là trạng
thái mới thì nó được thêm vào danh sách l_states. Các hàm chuyển trạng thái
được thêm vào danh sáchl_transtại dòng 7 trong Thuật toán 4.1. FSP M biểu diễn một kênh truyền tin được đặc tả như Hình 4.3.
S0 = (ack2,ack1→ S0 | snd1→ S1 | snd2→ S2), S1 = (snd2,snd1,out1,ack2→S0), S2 = (snd2,snd1,out2,ack1→S0). Hình 4.3: FSP M.
Dựa vào việc phân tích từ vựng và phân tích cú pháp của M ta thu được list_transitions chứa các phần tử có kiểu là (start_state, list_sub_trans).
Chương 4.Chuyển đổi giữa các dạng biểu diễn của LTS
Thuật toán 4.1Thuật toán chuyển đổi FSP sang LF.
Đầu vào: list_transitions là danh sách các tiến trình con.
Đầu ra: listing_form là kiểu dữ liệu LF.
1: Khởi tạo l_states = empty, l_trans = empty, init_state = null {l_ states là danh sách rỗng chứa các trạng thái, l_ trans là danh sách rỗng chứa các hàm chuyển trạng thái, init_state là trạng thái khởi tạo}
2: for all(start_state, list_sub_trans) in list_transitionsdo
3: ifl_states.exists(start_state) = falsethen
4: l_states.add(start_state) {thêm phần tử start_state vào danh sách l_states}
5: end if
6: for all(label, stop _state) in list_sub_transdo
7: l_trans.add((start_state, label, stop_state)) {thêm phần tử (start_state, la- bel, stop_state) vào danh sách l_trans}
8: ifl_states.exists(stop_state) = falsethen
9: l_states.add(stop_state) {thêm phần tử stop_state vào danh sách
l_states}
10: end if
11: end for
12: end for
13: (init, tail) = list_transitions.head() {lấy phần tử đầu danh sách
list_transitions}
14: init_state = init {gán init_state bằng init}
15: return new listing_form(init_state, l_states, l_trans) {trả về một đối tượng listing_form}
Chương 4.Chuyển đổi giữa các dạng biểu diễn của LTS Đầu vào: Danh sách list_transitions có các phần tử: [ (S0, [("ack2, ack1", S0), ("sdn1", S1), ("sdn2", S2)]), (S1, [("sdn2, sdn1, out1, ack2", S0)]), (S2, [("sdn2, sdn1, out2, ack1", S0)]) ] Các bước thực hiện: 1: Bước 1:
2: Khởi tạo các biến:
3: l_states = empty: là danh sách rỗng chứa các trạng thái
4: l_trans = empty: là danh sách rỗng chứa các hàm dịch chuyển
5: init_state = null: là trạng thái khởi tạo 6: Bước 2:
7: Duyệt danh sách list_transitions
8: Phần tử (S0, [("ack2, ack1", S0), ("sdn1", S1), ("sdn2", S2)]): 9: Thêm S0 và l_states
10: Gán list_sub_trans = [("ack2, ack1", S0), ("sdn1", S1), ("sdn2", S2)] 11: Duyệt danh sách list_sub_trans
12: Phần tử ("ack2, ack1", S0)
13: Thêm phần tử (S0, "ack2, ack1", S0) và l_trans
14: Tương tự đối với 2 phần tử ("sdn1", S1) và ("sdn2", S2) 15: Tương tự với 2 phần tử (S1, [("sdn2, sdn1, out1, ack2", S0)])
và (S2, [("sdn2, sdn1, out2, ack1", S0)]) 16: Bước 3:
17: Gán (init, tail) = List.hd (list_transitions)⇒init = S0 18: Gán init_state = S0
19: Bước 4:
Chương 4.Chuyển đổi giữa các dạng biểu diễn của LTS
4.1.2 Thiết kế
Mô hìnhFSP Compiler được mô tả bởi Hình 4.4. Trong mô hình 4.4 có 3 thành
phần chính là:Lexical Analyzer,ParservàTransitions Generator.FSP Compilersẽ có chức năng xử lý dữ liệu FSP đầu vào qua các bước phân tích từ vựng, phân tích cú pháp và sinh các chuyển trạng thái để đưa ra một danh sách cáctransitions.
Hình 4.4: Mô hình FSP Compiler.
Bước phân tích từ vựng được thực hiện bởi thành phần Lexical Analyzer
dưới sự hỗ trợ của Ocamllex. Lexical Analyzer cho kết quả đầu ra là các tokens. Các tokens là dữ liệu đầu vào của thành phần Parser. Bước phân tích cú pháp
được thực hiện bởi thành phầnParser.Parsersử dụngOcamlyaccđể hỗ trợ công
việc này. Parser sinh ra cây cú pháp tương ứng với dữ liệu FSP đầu vào. Cây
cú pháp được xử lý bởi thành phần Transitions Generator để sinh ra danh sách
chuyển trạng tháitransitions. Thành phần Transitions Generatorđược cài đặt dựa trên Thuật toán 4.1.
4.1.3 Phân tích đánh giá
Thuật toán 4.1 có tính dừng. Tham số đầu vào của Thuật toán 4.1 là một danh sáchlist_transitions. FSP là một máy hữu hạn trạng thái nên list_transitions là một danh sách hữu hạn phần tử. Thuật toán 4.1 sẽ kết thúc khi toàn bộ phần tử củalist_transitionsđược duyệt.
Phương pháp chuyển đổi từ FSP sang LF đã đặc tả và xử lý hoàn chỉnh đặc tả của ngôn ngữ FSP. Tuy nhiên, phương pháp này chưa được kiểm thử để đánh giá lỗi. Nhưng với sự hỗ trợ của công cụLTSA, chúng ta có thể so sánh được kết
Chương 4.Chuyển đổi giữa các dạng biểu diễn của LTS
4.2 Chuyển đổi LF sang FSP
4.2.1 Ý tưởng
Hệ thống sẽ cài đặt một thành phần được gọi là LF2FSP. Thành phần này có
chức năng chuyển đổi dữ liệu từ LF sang FSP. Bài toán chuyển đổi từ LF sang FSP được mô tả như Hình 4.5.
Hình 4.5: Cấu trúc thành phần chuyển đổi từ LF sang FSP.
AGTool sinh ra giả định dưới dạng LF và được thành phần LF2FSPxử lý.
Kết quả đầu ra của thành phầnLF2FSPlà dữ liệu FSP. Thành phần LF2FSPcài
Chương 4.Chuyển đổi giữa các dạng biểu diễn của LTS
Thuật toán 4.2Thuật toán chuyển đổi LF sang FSP.
Đầu vào: list_transitions là danh sách các hàm chuyển trạng thái, list_states là danh sách các trạng thái.
Đầu ra: fsp_str là chuỗi kí tự biểu diễn một FSP.
1: Khởi tạo fsp_str = null, count = 0, i = 0, tmp = empty
2: {khởi tạo xâu fsp_str rỗng, khởi tạo biến đếm count và i bằng 0, khởi tạo xâu tmp rỗng}
3: for allstate in list_statesdo
4: count := 0
5: tmp := null
6: for all(start_state, transition_label, stop_state) in list_transitionsdo
7: {Phương thức ReplaceCharInString dùng để thay thế một kí tự trong một
xâu bằng kí tự khác}
8: {Phương thức GetStopState dùng để kiểm tra xem một trạng thái có phải
là trạng thái kết thúc hay không?}
9: ifstart_state = state then
10: ifcount = 0then
11: tmp := tmp + (String.Uppercase start_state) + " = ({" + ReplaceCharIn- String transition_label ’=’ ’_’) + "} -> " + (GetStopState list_transitions stop_state)
12: else
13: tmp := tmp + "\n | {" + ReplaceCharInString transition_label ’=’ ’_’) + "} -> " + (GetStopState list_transitions stop_state)
14: end if 15: count++ 16: end if 17: end for 18: ifcount > 0then 19: i++ 20: ifi > 1then 21: fsp_str := fsp_str + ",\n" + tmp + ")" 22: else 23: fsp_str := fsp_str + tmp + ")" 24: end if 25: end if 26: end for 27: fsp_str fsp_str + ".\n"; 28: return fsp_str
Chương 4.Chuyển đổi giữa các dạng biểu diễn của LTS
Danh sáchlist_transitionsbao gồm các phần tử có định dạng là (start_state, transition_label, stop_state). Tại dòng 11 của Thuật toán 4.2 sẽ tìm ra các hàm chuyển có cùng trạng thái bắt đầu startstates. Nếu biến đếm count = 0 thì tạo mới một tiến trình con cho FSP. Ngược lại, tiến trình con sẽ được thêm vào FSP trước đó. Tại các dòng từ 20 đến 27, Thuật toán 4.2 xác định một tiến trình có phải là tiến trình bắt đầu của FSP hay không? Và FSP sẽ được thêm kí hiệu kết thúc vào cuối tại dòng 29.
Đầu vào:
Danh sách list_transitions: [(S0, "in", S1), (S1, "send", S2), (S2, "ack", S0)] Danh sách list_states: [S0, S1, S2]
Các bước thực hiện: 1: Bước 1:
2: Khởi tạo các biến:
3: fsp_str = null: là xâu rỗng
4: tmp = empty: là xâu rỗng
5: count = 0, i = 0: là các biến đếm 6: Bước 2:
7: Duyệt danh sách list_states 8: Gán count = 0, tmp = null 9: Phần tử S0:
10: Duyệt danh sách list_transitions 11: Phần tử (S0, in, S1): 12: count = 0 13: tmp = "S0 = (in -> S1" 14: count = 1 15: Phần tử (S1, send, S2): 16: S0 != S1 -> bỏ qua 17: Phần tử (S2, ack, S0): 18: S0 != S1 -> bỏ qua 19: (count = 1) > 0 -> i = 1
Chương 4.Chuyển đổi giữa các dạng biểu diễn của LTS
20: fsp_tmp = "S0 = ({in} -> S1)"
21: Tương tự đối với 2 phần tử S1 và S2, ta được:
22: fsp_tmp = "S0 = ({in} -> S1), S1 = ({send} -> S2),S2 = ({ack} -> S0)" 23: Bước 3:
24: Trả về chuỗi fsp_tmp biểu diễn một FSP
4.2.2 Phân tích đánh giá
Thuật toán 4.2 có tính dừng. Điều này có nghĩa là thuật toán kết thúc sau một khoảng hữu hạn thời gian thực thi. Tham số đầu vào của Thuật toán 4.2 là hai danh sách list_transitions và list_states. Trong Thuật toán 4.2, chương trình sẽ dừng khi duyệt hết toàn bộlist_transitionsvàlist_states. Các danh sách này đều là danh sách hữu hạn phần tử.
Luận văn đã trình bày phương pháp chuyển từ LF sang FSP. Tuy nhiên, kết quả thu được chưa được tối ưu hóa và phương pháp này chỉ mới được sinh ra FSP ở dưới dạng đơn giản nhất. Để giải quyết được bài toán này, cần phải dựa vào đặc tả và cú pháp của FSP. Sau đó cải tiến Thuật toán 4.2 để thu được xâu