Các định danh biểu tượng (Symbolic names) được dùng để khai báo một biểu tượng cho một số, một marco tiền xử lý có thể được dùng ở đầu chương trình.
# define max 10
Kiểu mtype (message type – kiểu thông điệp) được dùng để khai báo các định danh bộ nhớ cho các giá trị. Ưu điểm của mtype là các giá trị biểu tượng có thể được
in ra theo cấu trúc %e, và sau đó chúng sẽ xuất hiện trong phần lần vết (traces) của chương trình. Nhược điểm của mtype là nó chỉ có một tập các tên đã định nghĩa trước cho toàn bộ chương trình. Giá trị mtype có thể được in ra bằng lệnh printm.
c. Câu lệnh if
Lệnh if dùng để điều khiển các cấu trúc rẽ nhánh sẽ được khai báo theo cấu trúc:
if
:: điều kiện 1 -> thực hiện biểu thức 1 :: điều kiện 2 -> thực hiện biểu thức 2 :: điều kiện 3 -> skip
fi;
Trong Promela thì câu lệnh điều kiện được định nghĩa bằng cặp từ khóa if và
fi, cùng với cặp dấu hai chấm (::) định nghĩa điều kiện trong chương trình. Từ khóa
skip được dùng để thoát ra khỏi chương trình khi mà biểu thức đánh giá luôn có giá trị true hoặc (1).
d. Câu lệnh lặp do
Chỉ có một loại câu lệnh lặp trong Promela là câu lệnh do. Câu lệnh lặp do được khai báo tương tự như câu lệnh điều kiện if.
do
:: điều kiện 1 -> thực hiện biểu thức 1 :: điều kiện 2 -> thực hiện biểu thức 2 :: điều kiện 3 -> break
od;
Đoạn mã lệnh lặp được bao trong cặp từ khóa do và od, các lệnh ở bên trong đoạn mã được định nghĩa bởi cặp dấu hai chấm (::), để thoát khỏi vòng lặp thì ta dùng từ khóa break.
e. Câu lệnh nhảy jump
Promela cung cấp các câu lệnh nhảy đến một phần khác trong chương trình là
goto, break, skip. Lệnh nhảy goto có thể thay thế cho lệnh break trong vòng lặp, nhưng lệnh nhảy goto cần được chỉ định là sẽ nhảy đến phần nào của chương trình bằng một nhãn (label), còn lệnh break chỉ đơn giản là thoát ra khỏi vòng lặp.
4.1.2. Dữ liệu và cấu trúc chương trình
a. Kiểu mảng (array)
Tương tự như các ngôn ngữ lập trình khác, Promela cũng có dữ liệu kiểu mảng (array). Mảng trong Promela là mảng một chiều, muốn khai báo mảng hai chiều thì chúng ta cần dùng cách khác để thực hiện. Cấu trúc và ngữ nghĩa của mảng tương tự như trong ngôn ngữ lập trình C.
Các phần tử của mảng được khai báo tuần tự như sau:
Int Array[4];
Array[0] = 3; Array[1] = 12; Array[2] = 14; Array[3] = 32; Mảng của các dữ liệu kiểu bit hay bool sẽ được lưu trong mảng kiểu byte, để tiết kiệm bộ nhớ thì các kiểu dữ liệu khác cũng có thể lưu trong mảng kiểu byte bằng cách dịch chuyển bit (shift) và dùng mặt nạ (mask).
b. Định nghĩa kiểu (type definitions)
Các kiểu kết hợp được định nghĩa với typedef và thường được dùng để định nghĩa cấu trúc của các thông điệp được gửi qua các kênh:
typedef MESSAGE { mtype message; byte source; byte destination; bool urgent }
Kiểu tự định nghĩa này cũng được dùng để khai báo mảng 2 chiều trong Promela. Cú pháp của kiểu tự định nghĩa này tương tự với các ngôn ngữ giống C.
c. Bộ tiền xử lý (The preprocessor)
SPIN được cài đặt bằng ngôn ngữ C, nên nó cũng có những đặc tính tương tự C. Nó sử dụng một công cụ biên dịch được gọi là bộ tiền xử lý – nó sẽ được gọi trước khi bộ biên dịch thực thi. Bộ tiền xử lý cũng được dùng để dẫn dắt quá trình xử lý các macro dựa vào văn bản (text-based) trên mã nguồn. Dựa vào văn bản có nghĩa là bộ tiền xử lý không có bất kỳ tri thức nào về cú pháp và ngữ nghĩa của ngôn ngữ, thay vào đó là xem mã nguồn như là văn bản thuần.
Khi SPIN chạy ở bất kỳ mode nào, nó cũng gọi bộ tiền xử lý trước tiên, thông thường thì nó sẽ giống như là bộ tiền xử lý được kết hợp với bộ biên dịch dùng để biên dịch các bộ kiểm chứng.
Chúng ta có thể gặp các bộ tiền xử lý như #define, #include, và inline
tương tự như ngôn ngữ C trong SPIN.
#include “for.h” // Khai báo thư viện
#define N 5 // Định nghĩa một ký hiệu, nhãn
#define mutex (critical <=1) // Khai báo ký hiệu cho biểu thức
// được dùng trong các đặc tả tính // đúng đắn
Ngoài ra bộ tiền xử lý còn được cài đặt, ứng dụng trong việc biên dịch điều kiện (condition compilation), và các macro.
4.1.3. Cấu trúc kiểu kênh thông điệp và tiến trình
a. Dữ liệu kiểu kênh trong Promela
Một kênh trong Promela là một kiểu dữ liệu với hai toán tử: send và receive. Mỗi kênh kết hợp với một kiểu thông điệp (message type); một kênh sẽ phải được khởi tạo. Nó chỉ có thể gửi và nhận các thông điệp của loại thông điệp của nó. Có thể tạo được 255 kênh. Một kênh được khai báo với một khởi tạo đặc tả dung lượng kênh (channel capacity) và kiểu thông điệp:
chan ch = [capacity] of {typename, …, typename}
Dung lượng kênh phải là một hằng số nguyên không âm. Kiểu thông điệp đặc tả cấu trúc của mỗi thông điệp có thể được gửi trẻn kênh cũng như là một chuỗi của các trường; số trường; và kiểu của mỗi trường được đặc tả trong khai báo. Kiểu của một thông điệp không thể là kiểu mảng, tuy nhiên, thông điệp có thể có kiểu tự định nghĩa
typedefmà kiểu typedef có thể chứa một mảng trong đó.
Có hai loại kênh với ngữ nghĩa khác nhau: các kênh gặp (rendezvous channels) với dung lượng bằng không và các kênh đệm (buffered channels) với dung lượng lớn hơn không.
Hình 4.2 là đoạn mã Promela mô tả việc sử dụng kênh để gửi nhận dữ liệu trên hệ thống Client – Server. Trong chương trình ở hình 4.2 thì lệnh gửi (send statement) của Client0 có cấu trúc là request!0 trong đó request là tên kênh, dấu ! báo hiệu đây là kênh gửi, 0 là message gửi với đối số là 0. Lệnh nhận (receive statement) của Server có cấu trúc request?client nhận các yêu cầu từ client, dáu ? báo hiệu đây là kênh nhận.