1
ĐẠI HỌC QUỐC GIA HÀ NỘI
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ
NGUYỄN THU HƯỜNG
NGHIÊN CỨU VỀ PHÂN TÍCH CHƯƠNG TRÌNH
VÀ ỨNG DỤNG TRONG GIẢNG DẠY
Ngành:
Công nghệ thông tin
Chuyên ngành: Kỹ thuật phần mềm
Mã số:
60480103
LUẬN VĂN THẠC SĨ CÔNG NGHỆ THÔNG TIN
NGƯỜI HƯỚNG DẪN KHOA HỌC: PGS. TS. NGUYỄN VIỆT HÀ
HÀ NỘI - 2014
2
LỜI CAM ĐOAN
Tôi xin cam đoan kết quả đạt được trong luận văn là sản phẩm nghiên cứu, tìm
hiểu của riêng cá nhân tôi. Trong toàn bộ nội dung của luận văn, những điều được
trình bày hoặc là của cá nhân tôi hoặc là được tổng hợp từ nhiều nguồn tài liệu. Tất cả
các tài liệu tham khảo đều có xuất xứ rõ ràng và được trích dẫn hợp pháp.
Tôi xin hoàn toàn chịu trách nhiệm và chịu mọi hình thức kỷ luật theo quy định
cho lời cam đoan của mình.
Hà Nội, ngày 28 tháng 9 năm 2014
Người cam đoan
Nguyễn Thu Hường
3
MỤC LỤC
LỜI CAM ĐOAN ........................................................................................................ 2
DANH MỤC CÁC BẢNG .......................................................................................... 5
DANH MỤC CÁC HÌNH VẼ...................................................................................... 6
MỞ ĐẦU..................................................................................................................... 7
1. Bối cảnh ............................................................................................................. 7
2. Nội dung nghiên cứu .......................................................................................... 7
CHƯƠNG 1: KIẾN THỨC CƠ SỞ VỀ PHÂN TÍCH CHƯƠNG TRÌNH ................... 9
1.1. Khái niệm và phân loại Phân tích chương trình................................................ 9
1.2. Phân tích chương trình tĩnh .............................................................................. 9
1.2.1. Phương pháp tiếp cận dựa trên tri thức .................................................. 10
1.2.2. Sử dụng lý luận mờ trong việc hiểu chương trình dựa trên tri thức ........ 11
1.2.3. Phương pháp đánh giá chương trình tương tự ........................................ 13
1.3. Phân tích chương trình động .......................................................................... 20
1.4. Các ứng dụng chính của phân tích chương trình ............................................ 22
1.4.1. Chính xác hóa chương trình................................................................... 22
1.4.2. Tối ưu hóa chương trình ........................................................................ 22
1.5. Kết luận ......................................................................................................... 23
CHƯƠNG 2: CÂY CÚ PHÁP TRỪU TƯỢNG ......................................................... 24
2.1. Khái niệm ...................................................................................................... 24
2.2. Đặc trưng của cây cú pháp trừu tượng ........................................................... 24
2.3. Các công cụ sinh cây cú pháp trừu tượng từ mã nguồn .................................. 26
2.4. Các ứng dụng của cây cú pháp trừu tượng ..................................................... 27
2.4.1. Nhắc mã nguồn ..................................................................................... 27
2.4.2. Phát hiện lỗi mã nguồn trong thời gian thực .......................................... 28
2.4.3. Cây phác thảo mã nguồn thời gian thực ................................................. 28
2.4.4. Tìm kiếm mã nguồn .............................................................................. 28
2.4.5. Tối ưu hóa mã nguồn............................................................................. 28
2.4.6. Sơ đồ lớp đối tượng ............................................................................... 29
2.4.7. Tái cấu trúc mã nguồn ........................................................................... 29
CHƯƠNG 3: CÁC ĐƠN VỊ ĐO PHẦN MỀM .......................................................... 30
3.1. Các khái niệm về đơn vị đo phần mềm .......................................................... 30
3.1.1. Đơn vị đo phần mềm là gì?.................................................................... 30
3.1.2. Phân loại software metrics ..................................................................... 30
3.1.3. Giới hạn ................................................................................................ 34
3.2. Cyclomatic complexity .................................................................................. 35
3.2.1. Biểu đồ luồng điều khiển (Control flow graph – CFG) .......................... 35
3.2.2. Định nghĩa Cyclomatic Complexity ...................................................... 37
3.2.3. Cyclomatic Complexity và việc kiểm thử các đường tuyến tính độc lập 38
3.2.4. Hạn chế của Cyclomatic Complexity ..................................................... 39
4
CHƯƠNG 4: BÀI TOÁN ỨNG DỤNG TRONG GIẢNG DẠY ............................... 40
4.1. Mô tả bài toán................................................................................................ 40
4.2. Cách giải quyết bài toán ................................................................................ 42
4.2.1. Phân tích các đơn vị đo phần mềm ........................................................ 42
4.2.2. Phân tích sự tương tự về cấu trúc........................................................... 43
4.3. Ví dụ ............................................................................................................. 46
CHƯƠNG 5: THỰC NGHIỆM ................................................................................. 49
5.1. Các chức năng đã cài đặt được....................................................................... 49
5.2. Công nghệ và môi trường xây dựng mô hình thực nghiệm ............................. 49
5.2.1. JDK ....................................................................................................... 49
5.2.2. Netbean IDE.......................................................................................... 49
5.2.3. ANTLR ................................................................................................. 49
5.3. Cài đặt hệ thống............................................................................................. 50
5.3.1. Tạo ra cây cú pháp trừu tượng (AST) .................................................... 50
5.3.2. Thuật toán so sánh hai cây cú pháp trừu tượng ...................................... 56
5.4. Kết quả thực nghiệm...................................................................................... 57
5.4.1. Tính Cyclomatic complexity (CC) ......................................................... 57
5.4.2. So sánh sự tương tự về cấu trúc ............................................................. 58
5.5. Đánh giá kết quả thực nghiệm ....................................................................... 59
KẾT LUẬN ............................................................................................................... 60
TÀI LIỆU THAM KHẢO ......................................................................................... 61
5
DANH MỤC CÁC BẢNG
Bảng 1.1. Các đặc trưng của mã được sử dụng bởi Berghel and Sallach ................... 12
Bảng 1.2. Các thông số của Halstead ........................................................................ 14
Bảng 2.1 Các công cụ chuyển đổi mã nguồn thành AST ........................................... 27
Bảng 3.1 Ảnh hưởng của kiểu quyết định đến Cyclomatic complexity ...................... 38
Bảng 3.2 Một số phạm vi tiêu chuẩn của Cyclomatic complexity ............................. 39
Bảng 4.1 Các cột trong bảng dữ liệu BaiTap ............................................................. 45
Bảng 4.2 Các cột trong bảng dữ liệu GiaiPhap .......................................................... 46
Bảng 4.3 Các cột trong bảng dữ liệu tblKT_Dong .................................................... 46
6
DANH MỤC CÁC HÌNH VẼ
Hình 2.1 Hình ảnh của một cây cú pháp trừu tượng .................................................. 24
Hình 2.2 AST ở mức độ biểu thức ............................................................................ 25
Hình 2.3 AST thể hiện một phương thức trong java .................................................. 25
Hình 2.4 AST thể hiện một lớp trong java ................................................................. 26
Hình 3.1 Sơ đồ phân loại các đơn vị đo phần mềm ................................................... 31
Hình 3.2 Một ví dụ về CFG ...................................................................................... 35
Hình 3.3 Các cấu trúc cơ bản của CFG ..................................................................... 35
Hình 3.4 Một CFG đại diện cho một phương thức .................................................... 37
Hình 3.5 Một ví dụ cho các con đường kiểm thử dựa vào CC ................................... 39
Hình 4.1 Cách vận hành của hệ thống phân tích chương trình java của sinh viên ...... 40
Hình 4.2 Kiến trúc tổng thể của hệ thống phân tích ................................................... 41
Hình 4.3 Ví dụ một cây AST được sinh ra ............................................................... 44
Hình 4.4 Cấu trúc cơ sở dữ liệu của hệ thống ............................................................ 45
Hình 5.1 Kết quả khi cài đặt ANTLR thành công ...................................................... 52
Hình 5.2 Kết quả thực nghiệm về tính Cyclomatic complexity ................................. 57
Hình 5.3 Kết quả thực nghiệm chức năng so sánh cấu trúc trong trường hợp hai
chương trình giống cấu trúc ...................................................................................... 58
Hình 5.4 Kết quả thực nghiệm chức năng so sánh cấu trúc trong trường hợp hai
chương trình không giống cấu trúc ............................................................................ 59
7
MỞ ĐẦU
1. Bối cảnh
Phần mềm ngày càng đóng vai trò quan trọng trong xã hội hiện đại. Tỷ trọng giá
trị phần mềm trong các hệ thống ngày càng lớn. Tuy nhiên, trong nhiều hệ thống, lỗi
của phần mềm gây ra các hậu quả đặc biệt nghiêm trọng, không chỉ thiệt hại về mặt
kinh tế mà còn có thể làm tổn thất trực tiếp đến sinh mạng con người.
Theo [4]: “Có khoảng hơn 50% ngân sách của một dự án phần mềm được chi cho
các hoạt động liên quan đến nâng cao chất lượng phần mềm. Các nhà lãnh đạo ngành
công nghiệp khẳng định rằng đó là do sự quan tâm không đầy đủ đến chất lượng phần
mềm trong giai đoạn phát triển.”
Do đó việc trang bị các kỹ năng lập trình cho các lập trình viên là vô cùng quan
trọng ngay từ khi còn đang học đại học.
Lập trình là một hoạt động trí tuệ phức tạp và kỹ năng cốt lõi của sinh viên
CNTT năm đầu tiên. Các nghiên cứu đã chỉ ra rằng hầu hết các sinh viên đều có thể
viết các chương trình. Tuy nhiên, chương trình của sinh viên thường không được tối
ưu, vì chúng thường cố gắng giải quyết một vấn đề càng nhanh càng tốt mà không xem
xét các giải pháp khác nhau cho một chương trình, không cần suy nghĩ về chất lượng
các chương trình.
Cách tốt nhất để nâng cao chất lượng các chương trình của sinh viên là giảng
viên bàn luận với sinh viên về cách giải quyết một vấn đề cụ thể, từ đó thảo luận về
các bài tập mà sinh viên đã làm. Tuy nhiên, để nhận xét được tất cả các bài tập của
sinh viên và giúp sinh viên suy nghĩ về chất lượng các chương trình của mình là nhiệm
vụ khó khăn và tốn rất nhiều thời gian. Đặc biệt với quy mô lớp học hiện nay ở Việt
Nam (đông sinh viên) lại càng khó khăn hơn. Tự động phân tích các chương trình của
sinh viên có thể làm giảm sự khó khăn của vấn đề này. Hơn nữa tự động phân tích còn
làm cho quá trình chấm điểm của các giảng viên được nhanh hơn. Quan trọng hơn, nó
có thể giúp đưa ra mức độ đánh giá chi tiết hơn về chất lượng các chương trình của
sinh viên, giúp sinh viên nâng cao kỹ năng lập trình của mình.
Trong bối cảnh trên, đề tài nghiên cứu của tôi sẽ nghiên cứu về “Phân tích
chương trình” để ứng dụng vào kiểm tra các chương trình java của sinh viên.
2. Nội dung nghiên cứu
Trong luận văn này, nội dung nghiên cứu chính của tôi bao gồm:
Tìm hiểu các khái niệm liên quan và phân loại Phân tích chương trình. Đồng thời
tôi cũng tìm hiểu một số cách tiếp cận về hiểu chương trình tự động dựa vào Phân tích
chương trình tĩnh.
8
Có nhiều cách tiếp cận của Phân tích chương trình. Tuy nhiên tôi nghiên cứu hai
cách tiếp cận là: Phân tích dựa vào các đơn vị đo phần mềm (sofware metrics) và dựa
vào Phân tích cấu trúc của chương trình để đánh giá hai chương trình tương tự.
Trên cơ sở lý thuyết đã tìm hiểu, tôi xây dựng một chương trình để phân tích
đánh giá chương trình java của những sinh viên mới bắt đầu học lập trình (sinh viên
năm đầu tiên).
Các phần còn lại của luận văn có bố cục như sau:
Chương một là Kiến thức cơ sở về phân tích chương trình. Chương này, tôi sẽ
giới thiệu khái quát về phân tích chương trình, các ứng dụng, các kỹ thuật và một số
công cụ phân tích chương trình đã có.
Chương hai là Cây cú pháp trừu tượng (abstract syntax tree – AST). Chương này,
tôi sẽ trình bày về cây cú pháp trừu tượng. Tôi sẽ nêu lên ứng dụng của cây cú pháp
trừu tượng, đặc biệt là trong việc mô tả mã nguồn java phục vụ cho việc so sánh hai
chương trình tương tự.
Chương ba là các đơn vị đo phần mềm (Software metrics). Chương này, tôi sẽ
trình bày sơ lược về các đơn vị đo phần mềm sử dụng trong đánh giá phần mềm. Tôi
sẽ trình kỹ hơn về một đơn vị đo phần mềm là Cyclomatic complexity.
Chương bốn là Bài toán ứng dụng trong giảng dạy. Chương này tôi sẽ mô tả bài
toán để có thể ứng dụng trong giảng dạy cũng như các phương pháp, các công thức để
giải bài toán này.
Chương năm là Thực nghiệm. Chương này tôi sẽ trình bày về cách thức cài đặt
cũng như kết quả cài đặt hệ thống đánh giá chương trình của sinh viên mà tôi đã đặt ra
ở chương bốn.
9
CHƯƠNG 1: KIẾN THỨC CƠ SỞ VỀ PHÂN TÍCH CHƯƠNG
TRÌNH
Trong chương này, tôi sẽ trình bày các khái niệm liên quan đến Phân tích chương
trình, cũng như các kỹ thuật khác nhau và các ứng dụng của Phân tích chương trình.
1.1. Khái niệm và phân loại Phân tích chương trình
Theo [7]: “Trong khoa học máy tính, phân tích chương trình là quá trình tự động
phân tích hành vi của các chương trình máy tính.”
Theo [3, tr. 8], dựa vào việc chương trình có được thực hiện hay không, phân tích
chương trình có thể được chia làm hai loại chính:
+ Phân tích chương trình tĩnh
+ Phân tích chương trình động
Theo [4]: “Phân tích chương trình tĩnh là quá trình kiểm tra mã nguồn mà
không thực hiện chương trình. Nó được sử dụng để xác định vị trí các lỗi mã bao gồm
cả lỗi tiềm ẩn, các vùng phức tạp và dài dòng không cần thiết.”
Trong phân tích chương trình tĩnh, một chương trình được phân tích mà không
cần phải thực thi với một đầu vào cụ thể. Phân tích chương trình tĩnh thường mô tả các
kết quả có thể có cho một tập các yếu tố đầu vào (thường là cho tất cả các yếu tố đầu
vào của chương trình). Vì hành vi của một chương trình có thể khác nhau cho mỗi đầu
vào khác nhau cho nên phân tích tĩnh thường là mang ý nghĩa gần đúng. Thay vì đưa
ra kết quả chính xác, phân tích tĩnh thường đưa ra giới hạn trên và dưới của các giá trị
có thể.
Theo [4]: “Phân tích chương trình động là việc phân tích phần mềm máy tính
được làm bằng cách thực thi các chương trình trên một tập các dữ liệu đầu vào.”
Để hiểu được hành vi của chương trình, chúng ta thực hiện chương trình bằng
một số đầu vào, và sau đó kiểm tra đầu ra của nó. Để hiểu được chương trình tốt hơn,
chúng ta phải thực hiện chương trình với việc sử dụng nhiều bộ đầu vào khác nhau.
Điều này khiến việc phân tích chương trình động mất nhiều thời gian hơn so với phân
tích chương trình tĩnh. Tuy nhiên, phân tích chương trình động chính xác hơn phân
tích chương trình tĩnh, vì đầu ra của nó là kết quả từ một đầu vào cụ thể và có kiểm
chứng, chứ không phải là một tập hợp các giả định của cả đầu vào và đầu ra.
1.2. Phân tích chương trình tĩnh
Trong phân tích chương trình tĩnh, chương trình được phân tích bằng phương
pháp phân tích cấu trúc, mà không cần chạy mã lệnh. Phân chương trình tĩnh dựa trên
mã nguồn có thể được thực hiện bằng nhiều cách khác nhau. Ví dụ: phân tích tĩnh có
thể được dựa trên việc kiểm tra luồng điều khiển của chương trình, kiểm tra luồng dữ
10
liệu của chương trình, hoặc kiểm tra sự phức tạp của chương trình bằng cách sử dụng
các đơn vị (metrics) khác nhau, …
Hầu hết các nghiên cứu về sự hiểu chương trình tự động đều dựa trên Phân tích
chương trình tĩnh. Các phương pháp tiếp cận về việc hiểu chương trình tự động được
chia thành các loại sau:
+ Phương pháp tiếp cận dựa trên tri thức
+ Sử dụng lý luận mờ trong việc hiểu chương trình
+ Phương pháp tiếp cận đánh giá chương trình tương tự
+…
1.2.1. Phương pháp tiếp cận dựa trên tri thức
Theo [3]: “Kỹ thuật dựa trên tri thức được dựa trên các cơ sở tri thức được lưu
trữ và định nghĩa trước. Ý tưởng cơ bản của hiểu chương trình dựa trên tri thức chỉ
đơn giản là chúng ta so sánh mã nguồn đầu vào với các đoạn mã mẫu có trong thư viện.
Các đoạn mã này thường được gọi là các kế hoạch, các mẫu, các phân đoạn, … ”
Nếu chúng ta hiểu được các kế hoạch làm gì thì chúng ta có thể dễ dàng hiểu
được đoạn mã nguồn đó làm gì khi chúng ta tìm thấy một sự phù hợp giữa những đoạn
mã nguồn và một kế hoạch nào đó.
Sự hiểu chương trình dựa trên tri thức là quá trình tìm hiểu một chương trình về
mục tiêu của nó. Trong khái niệm này, viết một chương trình mới là một quá trình của
việc viết lại các mục tiêu của chương trình trong một tập hợp các mục tiêu con sử dụng
các kế hoạch như các quy tắc cho quá trình viết lại. Sự hiểu chương trình có thể được
coi là một quá trình ngược lại, là sự hiểu biết mục tiêu thông qua sự hiểu biết về các
mục tiêu con sử dụng các kế hoạch.
Các kế hoạch riêng biệt và đơn giản có thể được gộp lại thành một hình thức
phức tạp để tạo ra một chương trình. Các thuật toán có thể được coi là được hình thành
từ các kế hoạch. Ví dụ, như Letovsky và Soloway mô tả thuật toán mergesort có thể
được suy ra từ sự kết hợp một số kế hoạch: kế hoạch đệ quy trên cây nhị phân, kế
hoạch để tách một chuỗi thành hai, kế hoạch phân loại cặp số, và kế hoạch sát nhập
các danh sách được sắp xếp. Vì vậy, kế hoạch này không nên nhầm lẫn với các thuật
toán hoặc thủ tục vì chúng là các khái niệm khác nhau.
Phương pháp tiếp cận dựa trên tri thức có thể được chia làm 3 loại: Phương pháp
tiếp cận từ trên xuống, từ dưới lên và kết hợp cả hai.
Phương pháp chủ yếu là phương pháp tiếp cận từ dưới lên, có nghĩa là đầu tiên
chúng tôi cố gắng để nhận dạng và hiểu những đoạn mã nhỏ (còn gọi là các kế hoạch
cơ bản). Sau khi hiểu được các kế hoạch cơ bản, chúng tôi có thể tiếp tục quá trình
nhận ra và hiểu kế hoạch cấp cao hơn bằng cách kết hợp ý nghĩa của những kế hoạch
11
cơ bản đã được xác định. Tiếp tục quá trình này, cuối cùng chúng ta có thể kết luận
toàn bộ những gì mã nguồn sẽ làm.
Phương pháp tiếp cận từ trên xuống: ý tưởng ở đây là bằng cách biết được vấn
đề chính, chúng ta có thể lựa chọn kế hoạch đúng từ thư viện để giải quyết vấn đề cụ
thể và sau đó so sánh các mã nguồn với các kế hoạch. Nếu có một sự phù hợp giữa mã
nguồn và kế hoạch trong thư viện, chúng ta có thể trả lời câu hỏi về những gì mà
chương trình làm được.
Thêm vào đó, một số phương pháp lai giữa hai kỹ thuật từ trên xuống và kỹ thuật
từ dưới lên cũng được sử dụng. Một ví dụ về các phương pháp này là: Các kế hoạch
của chương trình đầu tiên được xác định (hiểu) bằng kỹ thuật từ dưới lên, sau đó kế
hoạch chung được đề xuất bởi hệ thống được so sánh với chương trình bằng cách từ
trên xuống. Các kế hoạch chung được đề xuất bằng cách sử dụng một thư viện kế
hoạch được tổ chức tốt, trong đó mỗi kế hoạch được đánh một chỉ mục, mục tiêu và ý
nghĩa liên kết đến các kế hoạch khác. Bằng cách sử dụng một cơ sở lập chỉ mục, hệ
thống có thể nhanh chóng kết hợp một phần của mã nguồn với một kế hoạch trong cơ
sở tri thức.
1.2.2. Sử dụng lý luận mờ trong việc hiểu chương trình dựa trên tri thức
Thay vì thực hiện nhiệm vụ so sánh mã với tất cả các kế hoạch, thì cách tiếp cận
thường được sử dụng trong việc hiểu chương trình dựa trên tri thức ở đây là:
Đầu tiên nó nhận ra một nhóm các câu lệnh như một phân vùng của mã gọi là
khối mã. Các khối mã, hoặc chỉ đơn giản là các khối – là các phần của mã có thể được
hiểu khác các phần khác của mã, và làm điều gì đó có ý nghĩa độc lập. Khối đôi khi
được coi như một bản mẫu, một kế hoạch, một lược đồ hoặc một cơ sở.
Lúc đầu, các khối tiềm năng được xác định từ mã nguồn. Trong các chương trình
lớn hơn, có thể có một số lượng lớn các khối tiềm năng được xác định. Do đó, có một
việc cần làm là phải bằng cách nào đó giảm con số này bằng cách chọn các khối có
triển vọng nhất từ các khối tiềm năng được gọi là khối ứng cử viên.
Ngay khi các khối ứng cử viên được hiểu, hệ thống sẽ chỉ lấy từ thư viện kế
hoạch ra những kế hoạch mà trông giống như những khối này. Nó xếp hạng các kế
hoạch theo sự tương đồng với mã và lựa chọn những kế hoạch xếp hạng cao nhất để
nghiên cứu và so sánh kỹ lưỡng hơn. Chi tiết của việc nghiên cứu và so sánh bao gồm
các thao tác tính toán giá trị mà không phải so sánh tất cả các kế hoạch với các mã sử
dụng trong các thao tác này. Vì vậy mà một lượng thời gian đáng kể có thể được tiết
kiệm.
Lý luận mờ được sử dụng cho việc tìm kiếm các kế hoạch tương tự nhất và xếp
hạng chúng. Để áp dụng lý luận mờ, đầu tiên chúng ta phải tìm những loại đặc trưng
12
của mã có thể phân biệt được và so sánh các mã, từ đó giúp chúng ta tìm thấy sự tương
đồng giữa các kế hoạch và khối.
Nghiên cứu bởi Berghel và Sallach đưa ra các đặc trưng của mã được sử dụng
như các phép đo tương tự. Những đặc trưng này được thể hiện trong Bảng 1.1.
Bảng 1.1. Các đặc trưng của mã được sử dụng bởi Berghel and Sallach
Code characteristics
Effectiveness[0 -1]
(Các đặc trưng)
(Ảnh hưởng)
Tổng số thao tác
0.99
Các lệnh gán
0.98
Tổng số toán hạng
0.95
Các biến thực
0.91
Khởi tạo
0.90
Tổng số biến
0.87
Các toán hạng duy nhất
0.85
Tổng số dòng
0.78
Các thao tác duy nhất
0.75
Từ khóa
0.52
Các ảnh hưởng ở mức thấp hơn
--
Sau khi chọn các đặc trưng mã thích hợp, bước tiếp theo là định lượng chúng. Có
nhiều cách tiếp cận khác nhau về định lượng các yếu tố đã lựa chọn. Phương pháp tốt
nhất và phù hợp nhất nên được lựa chọn là dựa trên ý nghĩa thông thường và có xem
xét bối cảnh và các loại vấn đề.
Bước tiếp theo là chuyển đổi các yếu tố định lượng thành ngôn ngữ tập mờ, ví dụ
LOW, MEDIUM và HIGH có nghĩa là tỉ lệ phần trăm thấp, trung bình và cao của sự
khác biệt giữa kế hoạch và các đoạn mã tương ứng.
Khi giá trị của từng yếu tố được tính toán, một bộ quy tắc được tạo ra. Những
quy tắc này sau đó được sử dụng trong lý luận: một biến đơn được tìm thấy các giá trị
khác nhau của các yếu tố khác nhau. Biến đơn này có thể được đặt tên, ví dụ
SIMILARITY thể hiện sự tương tự của kế hoạch cụ thể với khối lệnh. Một nguyên tắc
ví dụ như sau: nếu giá trị của số lượng biến là LOW và giá trị của toán hạng duy nhất
là MEDIUM, thì SIMILARITY là MEDIUM.
Bước cuối cùng trong quá trình lý luận bao gồm việc kết hợp các kết quả của các
quy tắc để tạo ra một con số đại diện cho kết quả cuối cùng: sự tương tự của khối lệnh
13
với kế hoạch. Có nhiều phương pháp khác nhau để tạo ra các quy tắc và kết hợp tạo ra
kết quả số cuối cùng, và phương pháp phù hợp nhất nên được lựa chọn tùy thuộc vào
vấn đề.
1.2.3. Phương pháp đánh giá chương trình tương tự
Phát hiện chương trình tương tự đã trở thành một chủ đề được quan tâm trong
một thời gian dài. Vấn đề chính trong nghiên cứu chương trình tương tự là để phát
hiện sao chép. Những công cụ này chủ yếu được sử dụng tại các trường đại học để
phát hiện ra sự sao chép bài giữa các sinh viên và ngăn chặn các sinh viên sao chép
của nhau.
Cách tiếp cận chương trình tương tự gồm nhiều phương pháp khác nhau. Nhiều
phương pháp thực hiện được quan tâm như các phương pháp phân tích tĩnh trên
chương trình chủ đề như: phân tích cấu trúc, phân tích luồng điều khiển và phân tích
luồng dữ liệu, …. Ngoài ra, các phương pháp thuộc tính đếm có thể được coi là một
thể loại con của việc nghiên cứu chương trình tương tự, kiểm tra mã nguồn dựa vào
các số lệu liên quan như các toán hạng, các toán tử, các lệnh gán, …. Đặc biệt là
những số liệu này có thể sẽ được sử dụng trong quá trình xác nhận một thuật toán.
Các phương pháp nghiên cứu đã được sử dụng trong phát hiện sao chép thay đổi
từ việc chỉ giải quyết vấn đề bằng cách đếm các thuộc tính của chương trình mà không
xem xét cấu trúc của chương trình, đến việc giải quyết vấn đề dựa vào cấu trúc của
chương trình. Một vài phương pháp thì sử dụng cả hai cách tiếp cận.
Các hệ thống phát hiện sao chép cũng có thể được phân loại dựa vào việc chúng
được thiết kế để kiểm tra ngôn ngữ tự nhiên, hoặc mã chương trình. Phát hiện sao chép
trong ngôn ngữ tự nhiên thường được coi là khó khăn hơn, vì sự không rõ ràng và
phức tạp của ngôn ngữ tự nhiên. Tuy nhiên có một số công cụ, có khả năng thực hiện
việc phát hiện sao chép với cả mã chương trình và ngôn ngữ tự nhiên.
Trong phần sau đây, tôi trình bày một số nghiên cứu về lĩnh vực này mà tôi đã
tìm hiểu được. Tôi chia các nghiên cứu thành hai loại chính, đó là phương pháp dựa
trên thuộc tính đếm và phương pháp dựa trên cấu trúc. Những nghiên cứu có sử dụng
cả hai phương pháp được mô tả trong thể loại thuộc tính đếm.
1. Phương pháp dựa trên thuộc tính đếm
Trong các phương pháp thuộc tính đếm một số đặc điểm của chương trình được
lựa chọn như là yếu tố quan trọng trong phân biệt các chương trình. Các đặc tính quan
trọng nhất đã được sử dụng là bốn thông số của Halstead được đề cập trong bảng 1.2.
Những đặc tính này được đếm từ mã chương trình, và kết quả được so sánh với kết
quả tương ứng thu được từ một mã chương trình khác trên cùng một thủ tục. Cuối
cùng, một số thể hiện sự tương tự giữa hai chương trình được tính toán từ việc áp dụng
một vài công thức.
14
Một trong những phương pháp tiếp cận đầu tiên dựa trên phương pháp này là
phương pháp tiếp cận Ottenstein có sử dụng các đặc trưng được đề cập trong Bảng 1.2
để phát hiện sao chép. Ottenstein cho rằng những đặc trưng này cho chúng ta một chỉ
số tốt để điều tra sự tương tự hoặc khác biệt giữa hai chương trình.
Bảng 1.2. Các thông số của Halstead
Ký hiệu
Giải thích
n1
Số các toán tử duy nhất
n2
Số các toán hạng duy nhất
N1
Tổng số các toán tử
N2
Tổng số các toán hạng
Trong phần tiếp theo, tôi mô tả các nghiên cứu khác sử dụng những đặc trưng
của mã để kiểm tra chương trình tương tự.
Cách tiếp cận của Donaldson và cộng sự
Donaldson và cộng sự phê phán phương pháp Ottenstein là quá rộng, xác suất để
hai chương trình được được coi là tương tự khi sử dụng phương pháp này là cao, mặc
dù bản thân Ottenstein cho rằng có một xác suất nhỏ cho điều này xảy ra. Donaldson
và cộng sự sử dụng phân tích cấu trúc để xác định sự giống nhau giữa hai chương trình.
Sử dụng phương pháp này, hai chương trình có thể được coi là giống nhau, mặc dù học
sinh có thể đã cố gắng làm cho chúng khác nhau bằng cách sử dụng một số phương
pháp đơn giản như:
1. Tên của các biến khác nhau
2. Thứ tự khác nhau giữa các lệnh khi thứ tự của các lệnh không làm thay
đổi chức năng của chương trình.
3. Vị trí khác nhau và hình thức khác nhau của lệnh khai báo.
4. Xuất hiện khác nhau trong các lệnh duy nhất như các lệnh khai báo biến
và lệnh xuất đầu ra.
Hệ thống được phát triển bởi Donaldson và cộng sự được mô tả như sau:
Hệ thống lấy các bài thi của sinh viên như là các tệp tin đầu vào, phân tích từng
bài trong đó và tạo ra một bảng có chứa thông tin về cấu trúc và nội dung của từng
chương trình. Sau khi xử lý các bài dự thi, hệ thống so sánh nội dung của bảng được
tạo ra từ mỗi chương trình với các bài dự thi khác. Nếu hai chương trình gửi từ 2
người khác nhau chỉ giống nhau ít nhất một trong bốn cách đề cập ở trên, thì họ được
gắn thẻ như là tương tự và gửi phản hồi trở lại. Hệ thống thu thập dữ liệu từ tất cả các
15
chương trình gửi đến. Mỗi loại lệnh được đưa ra một bộ đếm. Giá trị của bộ đếm được
tăng lên mỗi lần một câu lệnh tương ứng xảy ra trong chương trình. Sau đây là các thu
thập:
1. Tổng số các biến
2. Tổng số các chương trình con
3. Tổng số các lệnh đầu vào
4. Tổng số các lệnh điều kiện
5. Tổng số các lệnh lặp
6. Tổng số các lệnh gán
7. Tổng số các lời gọi chương trình con
8. Tổng số các lệnh của tất các kiểu từ 2-7
Từ các loại lệnh được liệt kê ở trên, một số được coi là quan trọng hơn trong việc
mô tả cấu trúc của chương trình hơn những lệnh khác. Các lệnh này được xử lý, những
lệnh khác bị bỏ qua. Hệ thống tiếp tục quét các chương trình đầu vào, thứ tự của các
lệnh được lưu trữ bằng cách sử dụng phương pháp mã hóa sau đây: Một chữ cái được
chọn để tham chiếu đến một câu lệnh. Khi một lệnh được đọc, thì chữ cái tương ứng sẽ
được thêm vào các mã theo thứ tự từ trái sang phải của các mã tương ứng với thứ tự từ
trên xuống dưới của câu lệnh trong chương trình. Một ví dụ về mã như là 'VVSD= = =
HI, các ký tự mã được gán cho các lệnh như sau:
V: lệnh khai báo
S: Chương trình con hoặc định nghĩa hàm
D: lệnh lặp
I: lệnh điều kiện If
H: lệnh lặp While
=: lệnh gán
Sau khi toàn bộ chương trình được quét, các mã được tạo ra sẽ được thêm vào
một mảng, chứa các mã tương ứng cho thứ tự của các loại câu lệnh trong các chương
trình khác cũng sẽ được thêm vào.
Sau giai đoạn thu thập dữ liệu, dữ liệu thu thập được phân tích. Giai đoạn phân
tích dữ liệu bao gồm hai giai đoạn chính: trong giai đoạn đầu tiên mức độ khác nhau
hoặc giống nhau giữa các bộ đếm của hai câu lệnh bất kỳ được tính toán. Kết quả của
phân tích này là một con số cho thấy sự giống nhau giữa mỗi cặp các câu lệnh. Trong
giai đoạn thứ hai, thứ tự lệnh của hai cặp lệnh được so sánh.
16
Giai đoạn đầu tiên bao gồm các phương pháp sau đây:
1. Tính tổng của sự khác biệt: Giá trị của bộ đếm cho mỗi cặp lệnh được trừ cho
nhau và giá trị tuyệt đối của phép trừ này là tổng. Kết quả thể hiện sự khác
nhau giữa hai chương trình.
2. Tính toán số các tương tự: Phương pháp này bao gồm việc tính toán các yếu
tố giống nhau giữa hai chương trình. Yếu tố tương tự cho thấy sự giống nhau
giữa hai chương trình được thiết lập có số không như giá trị ban đầu. Giá trị
của các yếu tố tương tự được tăng lên một hoặc vẫn không thay đổi phụ
thuộc vào việc các bộ đếm tương ứng giữa hai chương trình bằng nhau hay
không.
3. Tính toán số lượng các tương tự trọng điểm: Phương pháp này tương tự như
phương pháp trước, ngoại trừ thay vì cách tăng giá trị của các yếu tố tương tự
mỗi khi các bộ đếm tương ứng bằng nhau, giá trị của các yếu tố tương tự
được tăng một số cụ thể do giảng viên quy định. Điều này làm cho hệ thống
tương tác và cho phép người hướng dẫn nhấn mạnh tầm quan trọng của một
số loại lệnh cụ thể hoặc ngược lại. Ví dụ, nếu chương trình trong câu hỏi rất
đơn giản, bài của sinh viên có khả năng không chứa bất kỳ hàm con nào.
Điều này sẽ dẫn tăng giá trị của các yếu tố tương tự lên một, vì các bộ đếm
tương ứng sẽ được bằng nhau trong tất cả các chương trình. Người hướng
dẫn có thể loại bỏ ảnh hưởng của kiểu lệnh này bằng cách chỉ định một giá
trị bằng không cho nó.
Giai đoạn thứ hai, so sánh thứ tự giữa các lệnh như sau: Thứ nhất, các đặc trưng
mã tương tự được nén để sao cho không còn các ký tự giống nhau trong kết quả. Ví dụ,
Các mã đặc trưng 'VVSD === HI' trở thành 'VSD = HI. Vì một trong những cách phổ
biến mà học sinh thực hiện sao chép một chương trình rồi làm cho nó nhìn khác bản
gốc là tạo nhiều câu lệnh từ một câu lệnh đơn, thuật toán này làm giảm một loạt các
loại lệnh tương tự, làm cho thủ thuật này không hiệu quả. Sau đó, quá trình so sánh các
mã đặc trưng bắt đầu. Quá trình so sánh dừng lại, khi sự khác biệt đầu tiên giữa các
đặc trưng mã xuất hiện và cho kết quả là không sao chép. Nếu so sánh kết thúc mà
không có bất kỳ sự khác biệt nào thì một thông báo được in chỉ ra rằng đã tìm thấy sự
phù hợp (đã sao chép).
Phương pháp của Donaldson và các cộng sự có vẻ đơn giản và hiệu quả. Một số
điểm trong phương pháp của họ dường như thích hợp được áp dụng trong phân tích
chương trình. Tuy nhiên, cần lưu ý rằng giai đoạn thứ hai của phương pháp của họ, các
có vẻ không hiệu quả để sử dụng trực tiếp trong mục đích phân tích chương trình. Điều
này là do việc xóa các vòng lặp kế tiếp và các lệnh điều kiện để giảm số lượng của
chúng sẽ dẫn đến kết quả không chính xác trong phân tích chương trình.
17
Cách tiếp cận của Robinson và Soffa
Robinson và Soffa có cách tiếp cận khác [1]. Ngoài nhiệm vụ phát hiện sao chép,
hệ thống họ phát triển được gọi là ITPAD (Công cụ giảng dạy cho tư vấn chương
trình), được thiết kế để thực hiện các nhiệm vụ sau đây: điều tra xem liệu một sinh
viên có sử dụng một số cấu trúc liên quan đặc biệt trong chương trình của mình hay
không. Ví dụ, để thực hiện một nhiệm vụ cụ thể, sinh viên phải sử dụng một tập hợp
các thủ tục dự định mà đã được hướng dẫn trên lớp để hoàn thành nhiệm vụ đó, và
cuối cùng đưa ra gợi ý để cải thiện chương trình. Nó sử dụng các kỹ thuật tối ưu hóa
mã và các đơn vị đo phần mềm để phân tích chương trình. ITPAD bao gồm ba giai
đoạn: phân tích từ vựng, phân tích cấu trúc và phân tích các đặc trưng. Trong phần sau
đây, tôi sẽ trình bày từng giai đoạn:
Phân tích từ vựng bao gồm thu thập dữ liệu để có thể đếm các đặc trưng mã.
Các đặc trưng được sử dụng bởi Robinson và Soffa như sau:
1. Tổng số các biến duy nhất
2. Tổng số các biến
3. Tổng số các thao tác duy nhất
4. Tổng số các thao tác
5. chiều dài chương trình
6. Từ vựng của Chương trình
7. Khối lượng của chương trình
8. Mức độ của Chương trình
9. Nội dung thông tin
10. Nỗ lực của Chương trình
11. Tổng số lệnh gán
12. Tổng số lượng và loại cấu trúc điều khiển
13. Tổng số lượng và loại cấu trúc dữ liệu
14. Tổng số hàm và thủ tục con, tức là chương trình con.
Để có thể thực hiện nhiệm vụ của mình, ITPAD tạo ra hai cấu hình sử dụng các
đặc trưng mã: cấu hình sinh viên và cấu hình các lệnh. Bằng cách so sánh giải pháp
của mỗi sinh viên với các giải pháp mô hình, hệ thống có thể trả lời người hướng dẫn
rằng sinh viên đã có thể sử dụng các cấu trúc theo đúng yêu cầu chưa. Hệ thống này
cũng có thể báo cáo sự tiến bộ của sinh viên bằng cách so sánh trình độ của họ hiện tại
với các trình độ trước đó. Cấu hình cho lệnh bao gồm các báo cáo được tạo ra bởi
ITPAD về cách sinh viên đã giải quyết các câu lệnh, tức là: làm thế nào họ đã sử dụng
18
các cấu trúc điều khiển và cấu trúc dữ liệu, … Giai đoạn cấu hình lệnh sử dụng các kỹ
thuật tối ưu hóa chương trình.
Phân tích cấu trúc bao gồm các bước sau đây. Đầu tiên hệ thống phá vỡ các
chương trình đầu vào thành các khối cơ bản. Các khối cơ bản sau đó được tính toán và
so sánh với các khối cơ bản của chương trình mô hình. Số lượng các khối cơ bản cũng
cung cấp cho giảng viên ý tưởng về sự phức tạp trong các lệnh. Số lượng các khối cơ
bản được sử dụng trong việc phát hiện sao chép: nếu số lượng là như nhau trong hai
bài tập, và các bài tập có thể là có cấu trúc tương tự thì giảng viên cần xem xét chi tiết
hơn. Các bước khác trong phân tích cấu trúc là xây dựng biểu đồ luồng, xây dựng đồ
thị hở trực tiếp (DAG), thực hiện phân tích luồng dữ liệu và xác định các vòng lặp.
Các kết quả của các bước này được sử dụng trong giai đoạn tiếp theo để cung cấp cho
sinh viên một số đề xuất cải tiến, nếu cần thiết.
Phân tích các đặc trưng: các kết quả của phân tích trong giai đoạn trước được
xem xét trong giai đoạn này, và dựa trên kết quả của nghiên cứu này và kết quả so
sánh giữa bài làm của sinh viên và bài tập trong mô hình, đề nghị cải thiện được gửi
cho sinh viên. Ví dụ, cải thiện có thể như sau: lệnh tìm thấy không cần thiết cần loại
bỏ nó.
Như mô tả ở trên, mục đích chính của ITPAD dường như được cung cấp các đề
xuất cải thiện cho sinh viên, mặc dù nó có khả năng phát hiện sao chép tốt. Nói chung,
nó sử dụng một phương pháp kết hợp bằng cách sử dụng các số liệu và biểu đồ mô tả
chương trình.
2. Phương pháp dựa trên cấu trúc
Sau này, các nghiên cứu về phát hiện sao chép tập trung vào phân tích cấu trúc,
chứ không phải là phân tích các đặc trưng. Các phương pháp dựa trên cấu trúc tỏ ra
nhiều hiệu quả hơn trong việc phát hiện sao chép giữa các sinh viên. Phương pháp dựa
trên cấu trúc có thể được chia thành hai thể loại nhỏ: hệ thống dựa trên chuỗi phù hợp
và hệ thống dựa trên cây phù hợp. Như Maxim Mozgovoy mô tả dựa trên hệ thống
chuỗi phù hợp sử dụng phương pháp so sánh sự khác nhau của các chuỗi.
Cách tiếp cận của Joy và Luck
Mike Joy và Michael Luck giới thiệu một cách tiếp cận mới trong vấn đề phát
hiện sao chép. Họ cho rằng việc thiếu nhiều tính năng hấp dẫn trong các hệ thống phát
hiện sao chép trước đã thúc đẩy họ phát triển cái mới. Như một ví dụ về các tính năng
mong muốn còn thiếu, họ đề cập đến việc là thực tế một hệ thống phát hiện sao chép
nên dễ dùng và có thể dùng được khi thay đổi sang một ngôn ngữ khác, vì một sinh
viên có khả năng sử dụng nhiều hơn một ngôn ngữ trong suốt khóa học. SHERLOCK
là hệ thống được phát triển bởi Mike Joy và Michael Luck so sánh hai chương trình
năm bước sau:
19
1. chương trình ban đầu
2. Chương trình với tối đa số lượng khoảng trắng đã xóa
3. Chương trình với tất cả các chú thích đã loại bỏ
4. Chương trình với tất cả các chú thích và tối đa số khoảng trắng đã xóa
5. Chương trình khi chuyển sang dạng thẻ từ (token)
Một hoặc nhiều lần phù hợp giữa hai chương trình trong suốt thời gian so sánh
qua năm bước này cho thấy khả năng tương đồng giữa các chương trình và đây là lý
do đưa ra để kiểm tra thêm. Tất cả các chương trình được so sánh với nhau và trình tự
tương tự được lưu trong một tệp tin. Hai chuỗi được coi là tương đương nếu sự khác
biệt giữa chúng không vượt quá một giá trị được xác định trước (giá trị này có thể thay
đổi được bởi người giảng viên). Ví dụ, 10 dòng sắp theo thứ tự được đánh dấu là tương
tự theo mặc định, nếu chỉ có một dòng thêm vào và một dòng mất đi; nhưng không
được đánh dấu tương tự, nếu số lượng dòng bổ sung và dòng mất đi tương ứng là 3 và
3. Họ cho rằng việc xây dựng hệ thống chỉ đơn thuần dựa trên sự so sánh trình tự giữa
các từ thì thông báo sẽ cho kết quả sai đặc biệt là trong các lớp học giới thiệu về lập
trình (không có quá nhiều thuật toán thay thế để thực hiện một nhiệm vụ). So sánh gia
tăng này đảm bảo rằng những sự phù hợp không cần thiết không xảy ra.
Sau khi tất cả các chương trình đã được so sánh, một mạng nơ ron được gọi để
tạo ra một tập tin thị giác PostScript (tệp tin lưu lại mô tả sự giống nhau giữa các
chương trình). Trong tập tin PostScript được tạo ra, các tập tin ban đầu được thể hiện
như là các điểm và sự giống nhau giữa hai điểm được minh họa bằng một đường nối
giữa hai điểm này. Không có ranh giới giữa điểm hoàn toàn khác nhau. Chiều dài của
đường vẽ giữa hai điểm chỉ ra mức độ tương tự giữa hai điểm: dòng ngắn hơn, dài hơn
là giống nhau. Trực quan kết quả của sự so sánh giữa các chương trình có thể giúp
người giảng viên có được một sự hiểu biết nhanh chóng về sự tương đồng giữa các
chương trình.
Cách tiếp cận của Gitchell và Tran
Sim là một hệ thống được phát triển để phát hiện sự giống nhau giữa các chương
trình C. Sim tạo ra một chuỗi các thẻ từ mã nguồn của chương trình (loại bỏ các
khoảng trống, các chú thích và tất cả các phần không cần thiết khác). Sau đó, Sim sử
dụng thuật toán liên kết chuỗi để so sánh hai chương trình. Sự giống nhau giữa hai
chương trình được chỉ định bởi một số nằm trong khoảng 0.0 đến 1.0.
Cách tiếp cận của Schleimer và cộng sự
MOSS là một hệ thống phát hiện sao chép dựa trên chuỗi phù hợp. Ba khía cạnh
được cho là quan trọng bởi các nhà phát triển khi thiết kế hệ thống là: các đặc trưng
không cần thiết như các khoảng trắng và các phần khác mà không làm ảnh hưởng đến
kết quả, các từ thông thường và cách diễn đạt không nên giống nhau và thay đổi cấu
20
trúc của mã nguồn chương trình, loại bỏ hoặc thêm các phần không làm ảnh hưởng
đến kết quả. Những điều này được xem xét như sau: Khi thẻ từ hóa mã chương trình,
tất cả các chữ được chuyển đổi thành chữ thường và tất cả các đặc trưng không quan
trọng bao gồm hệ thống các loại chấm câu được loại bỏ. Các thuật toán chuỗi phù hợp
sau đó được áp dụng để thực hiện các so sánh. Vấn đề thứ hai nêu ở trên được giải
quyết bằng cách chọn một phần dài vừa đủ chuỗi các từ để so sánh, sao cho các từ
thông thường và cách diễn đạt là ngắn hơn so với ngưỡng được lựa chọn này.
Cách tiếp cận phù hợp với cây, trong phương pháp này, đầu tiên các mã chương
trình được phân tích và cây cú pháp trừu tượng được tạo ra. Cây cú pháp trừu tượng
sau đó được sắp xếp theo thứ tự của các nút theo một đường thẳng. Điều này được
thực hiện trong một quá trình, mà Kim và Choi gọi là "unparsing". Việc so sánh giữa
hai chương trình được thực hiện trên những chuỗi các nút. Sự tương tự được chỉ định
bởi các giá trị thay đổi từ 0 đến 1, 1 có nghĩa là hai chương trình là hoàn toàn tương tự.
Phương pháp này sử dụng một thuật toán nhanh hơn khi bắt đầu để đảm bảo rằng hai
chương trình này không hoàn toàn khác nhau. Tiếp tục điều tra chi tiết được thực hiện
trừ khi hai chương trình xuất hiện một vài khu vực giống nhau. Bằng cách này, số
lượng so sánh được giảm dẫn đến cải thiện sự hiệu quả.
1.3. Phân tích chương trình động
Trong phân tích chương trình động, chương trình được thực hiện bởi một bộ
kiểm thử đầu vào, và đầu ra sau đó được nghiên cứu để hiểu các chức năng của
chương trình. Để phân tích các chương trình kỹ lưỡng và hiểu các chức năng của nó
một cách toàn diện, phải thực hiện rất nhiều bộ kiểm thử.
Phân tích chương trình động thường được sử dụng trong các hệ thống đánh giá tự
động - sự chính xác của các bài tập của sinh viên được kiểm tra bằng cách chạy
chương trình của họ sử dụng một số đầu vào kiểm thử, và so sánh giá trị của nó với
một trong những đầu ra mong đợi.
Trong phần sau đây, tôi trình bày tổng quan về một số hệ thống đánh giá tự động
mà tôi đã tìm hiểu được. Dưới đây tôi trình bầy các hệ thống đánh giá tự động được sử
dụng bởi đội ngũ giảng viên tại các trường đại học trong nhiệm vụ đánh giá các bài tập
của sinh viên. Bài tập của sinh viên có thể được chia thành nhiều loại bao gồm: bài tập
nhiều lựa chọn, bài tập lập trình, câu trả lời trực quan, câu trả lời văn bản và đánh giá
ngang hàng. Các hệ thống đánh giá tự động khác nhau có khả năng đánh giá các loại
bài tập khác nhau.
ASSYST
Phát triển tại Đại học Liverpool, ASSYST là một hệ thống đánh giá tự động
chấm điểm các bài tập của sinh viên dựa trên năm đơn vị đo: sự chính xác, sự hiệu quả,
sự phức tạp, phong cách, và an toàn dữ liệu. Nó được áp dụng phương pháp phân tích
động để đánh giá tính đúng đắn của mã lệnh. Đầu tiên giảng viên viết một mô hình đặc
21
tả về đầu ra mà các chương trình phải làm. Sau đó, bài tập của sinh viên được thực
hiện và đầu ra của nó được so sánh với đầu ra của mô hình sử dụng phương pháp tiếp
cận phù hợp mẫu. ASSYST sử dụng công cụ Unix Lex và Yacc để kiểm tra xem các
đầu ra mà chương trình của sinh viên có phù hợp với các đầu ra mô hình hay không.
ASSYST cũng áp dụng phân tích tĩnh với mức độ: nó phân tích các khối chương trình
và đếm tất cả các lệnh trong mỗi khối để đo sự hiệu quả và sự an toàn dữ liệu.
Ceilidh and CourseMarker
Ceilidh là một hệ thống đánh giá tự động giống như ASSYST, phân tích động
các bài tập của sinh viên. Như ASSYST, nó chạy chương trình với một bộ dữ liệu thử
nghiệm, và sau đó kiểm tra đầu ra để xác định xem các đầu ra phù hợp với đầu ra mô
hình (được tạo ra bởi giải pháp mô hình). Để đánh giá độ phức tạp của mã nguồn,
Ceilidh sử dụng công cụ lint Unix C để thực hiện phân tích tĩnh trên mã và đếm số
lượng các lệnh điều kiện, các vòng lặp, cũng như các biến không được sử dụng.
CourseMarker (trước đây gọi là CourseMaster) là một phiên bản kế nhiệm của
Ceilidh được cải thiện với các tính năng mới như: hỗ trợ mạng, giao diện cửa sổ, hiệu
suất tốt hơn, hệ thống thông tin phản hồi tốt hơn, bảo trì và khả năng mở rộng. Ngoài
ra, không giống như Ceilidh là chỉ chạy trên nền tảng UNIX, CourseMarker chạy trên
cả nền tảng UNIX và Windows, vì nó được phát triển bằng Java.
Scheme-robo
Scheme-robo, một hệ thống phân tích các chương trình lược đồ, về cơ bản là
tương tự như các hệ thống trên: nó phân tích động trên mã nguồn các bài tập của sinh
viên để đánh giá chúng. Scheme-robo chỉ đơn giản là thực thi mã lệnh sử dụng chạy
các bộ test khác nhau và kiểm tra kết quả. Tuy nhiên, Scheme-robo thực hiện đánh giá
dựa trên giá trị đầu ra của chương trình sinh viên mà không so sánh với đầu ra với các
kết quả mô hình. Scheme-robo thực hiện phân tích tĩnh khá tốt. Ví dụ, nó kiểm tra mã
để đảm bảo rằng một số từ khóa cụ thể không được tìm thấy trong các bài tập. Điều
này là bởi vì nếu sinh viên được yêu cầu thực hiện một chức năng cụ thể, và ngôn ngữ
có tích hợp một số chức năng tiện ích để làm chức năng đó, sinh viên không được
phép sử dụng tiện ích này. Scheme-robo sử dụng phân tích tĩnh để chuyển đổi mã
thành một cây cú pháp trừu tượng khá tốt. Sau đó nó sử dụng cây cú pháp trừu tượng
để kiểm tra các chương trình khác, ví dụ trong nhiệm vụ phát hiện sao chép.
Boss
Phát triển bởi Joy và các cộng sự, Boss là một công cụ trực tuyến đánh giá các
lệnh tự động, nó thực hiện cả phân tích tĩnh và động. Ví dụ: trong việc phát hiện sao
chép. Giáo viên đánh giá bài tập nộp về của sinh viên từ các quan điểm khác nhau, ví
dụ: nó sử dụng một số đơn vị để kiểm tra cách lập trình, ví dụ như: sử dụng các chú
thích, kiểm tra các bài dự thi để tìm các chương trình ăn cắp ý tưởng, kiểm tra để xác
thực, kiểm tra các bài dự thi cho đúng đắn sau đó nó đánh dấu mỗi bài và cho ý kiến
22
phản hồi cho người nộp. Tính chính xác của bài tập của học sinh được kiểm tra sử
dụng hai kỹ thuật khác nhau: chạy chương trình sử dụng một số dữ liệu thử nghiệm và
sau đó điều tra các tập tin đầu ra và sử dụng JUnit (khi câu hỏi yêu cầu sử dụng ngôn
ngữ java).
1.4. Các ứng dụng chính của phân tích chương trình
Theo [7]: “Các ứng dụng chính của phân tích chương trình là chính xác hóa
chương trình và tối ưu hóa chương trình.”
1.4.1. Chính xác hóa chương trình
Theo [12]: “Trong lý thuyết khoa học máy tính, sự chính xác của một thuật toán
được khẳng định khi nó chính xác với một mô tả cụ thể nào đó. Hàm chính xác liên
quan đến các hành vi vào ra của thuật toán (nghĩa là với mỗi đầu vào thuật toán sẽ cho
kết quả đầu ra chính xác).”
Theo [13, tr 3]: “Một chương trình chính xác là một chương trình thực hiện chính
xác những gì nó được mô tả không hơn không kém.”
Một chương trình chính xác chính quy là chương trình mà độ chính xác của nó có
thể được chứng minh bằng phương pháp toán học. Điều này đòi hỏi ngôn ngữ phải mô
tả chính xác những gì mà chương trình dự định làm. Sự rõ ràng của ngôn ngữ dựa trên
toán học logic. Hoare đã phát minh ra “ngữ nghĩa tiên đề” vào năm 1969, nó như là
một công cụ để xác định hành vi và chứng minh tính đúng đắn của chương trình.
Theo [12]: “Logic Hoare là một hệ thống chính quy có lý luận chặt chẽ về sự
chính xác của các chương trình máy tính.”
Cho đến gần đây, sự chính xác (Correctness) đã trở thành một dạng bài tập trong
các trường đại học. Và bây giờ nó trở thành một yếu tố quan trọng trong các hệ thống
phần mềm .
Theo [13, tr 4], một số công cụ chính xác hóa (Correctness Tools ):
+ Chứng minh định lý (Theorem provers): PVS
+ Ngôn ngữ mô hình hóa (Modeling languages): UML and OCL
+ Ngôn ngữ đặc tả (Specification languages): JML
+ Hỗ trợ ngôn ngữ lập trình (Programming language support): Eiffel, Java,
Spark/Ada
+ Đặc tả các phương pháp (Specification Methodology): Design by contract
1.4.2. Tối ưu hóa chương trình
Theo [14]: “Trong khoa học máy tính, tối ưu hóa chương trình (hay tối ưu hóa
phần mềm) là quá trình sửa đổi hệ thống phần mềm để phần mềm làm việc hiệu quả
23
hơn (ở khía cạnh nào đó) hoặc sử dụng ít tài nguyên hơn. Nói chung một chương trình
máy tính có thể được tối ưu hóa để nó thực hiện nhanh hơn, hoặc nó hoạt động với bộ
nhớ lưu trữ ít hơn, hoặc tốn ít các tài nguyên khác hơn.”
Ta có thể tối ưu hóa chương trình ở các cấp độ khác nhau như: cấp độ thiết kế
(liên quan đến tối ưu các thuật toán), cấp độ mã lệnh, …
Các công cụ phân tích chương trình ngày nay dần dần đi đến chức năng đưa ra
các phản hồi cho lập trình viên nhằm tối ưu hóa chương trình.
1.5. Kết luận
Chương này, tôi đã trình bày các khái niệm cơ bản của Phân tích chương trình.
Đặc biệt tôi đã trình bày một số hướng tiếp cận của việc hiểu chương trình tự động dựa
trên phân tích tĩnh. Đây là một lĩnh vực nghiên cứu khá rộng, tuy nhiên tôi không có
tham vọng nghiên cứu tất cả các kỹ thuật cũng như phương pháp tiếp cận của Phân
tích chương trình. Tôi chỉ tập chung nghiên cứu về phân tích tĩnh mã nguồn dựa vào
hai cách tiếp cận sau:
Thứ nhất là đánh giá hai chương trình tương tự. Chương trình mẫu và chương
trình của sinh viên được chuyển thành dạng cây cú pháp trừu tượng. Sau đó hai cây cú
pháp này được so sánh với nhau và phản hồi lại cho sinh viên về giải pháp của chúng.
Thứ hai là đánh giá độ phức tạp của chương trình sinh viên sử dụng các đơn vị
đo phần mềm (Software metrics). Ở luận văn này tôi sẽ nghiên cứu kỹ và cài đặt đơn
vị đo Cyclomatic complexity.
24
CHƯƠNG 2: CÂY CÚ PHÁP TRỪU TƯỢNG
2.1. Khái niệm
Theo [15]: “Cây cú pháp trừu tượng – Abstract syntax tree (AST) là một cây đại
diện cho cấu trúc ngữ pháp trừu tượng của mã nguồn được viết bằng một ngôn ngữ lập
trình nào đó. Mỗi nút của cây thể hiện một cấu trúc đang có của mã nguồn. Cấu trúc là
“trừu tượng” nghĩa là nó không đại diện cho tất cả các chi tiết xuất hiện trong cú pháp
thực”.
Ví dụ, hình 2.1 là một cây AST thể hiện cho đoạn mã nguồn sau:
while(b!=0)
if(a>b)
a=a-b;
else
b=b-a;
Hình 2.1 Hình ảnh của một cây cú pháp trừu tượng
2.2. Đặc trưng của cây cú pháp trừu tượng
Đặc trưng của AST thể hiện rõ ở mức độ biểu thức, các nút bên trong thể hiện
các toán tử (operator), các nút lá của nó thể hiện các toán hạng (operands) của toán tử.
Ví dụ, biểu thức “a=2+3” trong java được thể hiện bởi AST như hình 2.2
25
Hình 2.2 AST ở mức độ biểu thức
Ngoài đặc trưng trên thì ở AST còn giản lược một số thành phần cú pháp không
cần thiết cho các giai đoạn kế tiếp của trình biên dịch như các dấu ngoặc đơn, ngoặc
kép, dấu chấm phẩy, dấu phẩy…
Ví dụ, hình 2.3 là AST của một phương thức sau trong java:
public int abs(int a)
{
if(a>=0)
return a;
return –a;
}
Hình 2.3 AST thể hiện một phương thức trong java