Đó là một tập hợp các quy tắc về cấu tạo từ và quy tắc về cách thức liên kết lại câu.Bằng cách áp đặt một số hạn chế trên các luật sinh Chomsky đề nghị một hệ thống phân loại văn phạm dự
Trang 1
Phụ Lục Đặt vấn đề 2
PHẦN MỘT : CƠ SỞ LÝ THUYẾT 3
I VĂN PHẠM PHI NGỮ CẢNH VÀ NGÔN NGỮ PHI NGỮ CẢNH 3
1.Khái niệm văn phạm 3
2.Khái niệm văn phạm phi ngữ cảnh 3
3 Ngôn ngữ phi ngữ cảnh 3
II DẪN XUẤT 4
1 Dẫn xuất trực tiếp và dẫn xuất gián tiếp 4
2 Dẫn xuất trái nhất và dẫn xuất phải nhất 4
III CÂY DẪN XUẤT 5
1 Khái niệm: 5
2 Mối quan hệ giữa dẫn xuất và cây dẫn xuất 5
PHẦN HAI : CẤU TRÚC CHƯƠNG TRÌNH 6
I Cấu Trúc Chương Trình 6
1 Xử lý chuỗi nhập 6
2 In ra dẫn xuất 7
3 Vẽ cây 9
II Sơ Đồ Khối Của Chương Trình 13
III Các Giao Diện Chính 14
Danh mục tài liệu tham khảo: 16
Trang 2Đặt vấn đề
Ngôn ngữ hình thức (Formal Languages) là môn học cơ sở của ngành công nghệ thông tin Nó cho phép nghiên cứu, xây dựng mô hình toán học cho các máy tính toán Đặc biệt trong xây dựng mô hình toán cho ngôn ngữ
tự nhiên Kiến thức về ngôn ngữ hình thức và automat là nền tảng cho nhiều lĩnh vực của khoa học máy tính và CNTT
Trong nghiên cứu về ngôn ngữ hình thức tập trung vào nghiên cứu các loại văn phạm Đó là một tập hợp các quy tắc về cấu tạo từ và quy tắc về cách thức liên kết lại câu.Bằng cách áp đặt một số hạn chế trên các luật sinh Chomsky đề nghị một hệ thống phân loại văn phạm dựa vào cấu trúc của các luật sinh Bao gồm 4 loại văn phạm là: văn phạm loại 0, văn phạm loại 1, văn phạm loại 2 và văn phạm loại 3
Văn phạm phi ngữ cảnh(văn phạm loại 2): là một loại văn phạm khá quan trọng Việc nghiên cứu các văn phạm phi ngữ cảnh đã tạo nên một cơ sở lý luận vững chắc cho việc biểu diễn ngôn ngữ lập trình, việc tìm kiếm các giải thuật phân tích cú pháp, vận dụng trong chương trình dịch và cho nhiều ứng dụng khác về xử lý chuỗi Chẳng hạn, nó rất hữu ích trong việc mô tả các biểu thức số học với nhiều dấu ngoặc lồng nhau hoặc cấu trúc khối trong ngôn ngữ lập trình mà biểu thức chính quy không thể đặc tả Trong văn phạm phi ngữ cảnh có rất nhiều khâu để xử lý, phân tích Trong phạm vi của đồ án, chúng em xin trình bày những cơ sở lý thuyết về văn phạm phi ngữ cảnh(CFG) đồng thời lập trình đưa ra dẫn xuất và cây dẫn xuất của văn phạm
đã cho.Do lượng kiến thức còn hạn chế nên trong quá trình thực hiện đồ
án còn nhiều thiếu sót mong các thầy đóng góp ý kiến để chúng em hoàn thiện đồ án
Trang 3PHẦN MỘT : CƠ SỞ LÝ THUYẾT
I VĂN PHẠM PHI NGỮ CẢNH VÀ NGÔN NGỮ PHI NGỮ CẢNH
1.Khái niệm văn phạm.
Văn phạm G là một bộ gồm 4 thành phần G = < Σ, Δ, S, P >, trong đó:
- Σ : bảng chữ cái, gọi là bảng chữ cái cơ bản (bảng chữ cái kết thúc
– terminal symbol);
- Δ , Δ ∩ Σ =Ø, gọi là bảng ký hiệu phụ (bảng chữ cái không kết thúc
– nonterminal symbol);
- S ∈ Δ - ký hiệu xuất phát hay tiên đề (start variable);
- P : tập các luật sinh (production rules) dạng α→β, α, β ∈ (Σ ∪ Δ)*,
trong α chứa ít nhất một ký hiệu không kết thúc (đôi khi, ta gọi chúng là các qui tắc hoặc luật viết lại)
2.Khái niệm văn phạm phi ngữ cảnh
Định nghĩa:
Một văn phạm phi ngữ cảnh được định nghĩa : G = < Σ, Δ, S, P >
Trong đó:
- : là bảng chữ cái
- Δ : là tập các kí tự không kết thúc (biến)
- S N là kí tự xuất phát
- P: là tập các luật sinh, mỗi luật sinh có dạng : A ->
A Δ và (Δ )*
3 Ngôn ngữ phi ngữ cảnh
Định nghĩa: ngôn ngữ L được gọi là ngôn ngữ phi ngữ cảnh nểu tồn tại một
văn phạm phi ngữ cảnh G sao cho L= L( G)
Trang 4Như vậy : thì một ngôn ngữ chính quy cũng là ngôn ngữ phi ngữ cảnh, hay nói cách khác lớp các ngôn ngữ chính quy là tập con trong lớp các ngôn ngữ phi ngữ cảnh
II DẪN XUẤT
1 Dẫn xuất trực tiếp và dẫn xuất gián tiếp
Dẫn xuất trực tiếp :Nếu A →b là luật sinh trong văn phạm G và α, β là
2 chuỗi bất kỳ, thì khi áp dụng luật sinh A →b vào chuỗi αAβ ta sẽ thu được chuỗi αbβ αAβ → αbβ
Dẫn xuất gián tiếp: Giả sử: a1→ a2, a2→ a3, , am-1→ am ta viết a1→ *am
(chú ý rằng a→ *a với mọi chuỗi a)
2 Dẫn xuất trái nhất và dẫn xuất phải nhất
Dẫn xuất trái nhất: Để giới hạn sự lựa chọn các luật sinh trong quá
trình dẫn xuất, nếu mỗi bước biến bên trái nhất của dạng câu được thay thế thì ta gọi là dẫn xuất trái nhất
Dẫn xuất phải nhất: Tương tự như dẫn xuất trái nhất nếu mỗi bước biến
bên phải nhất của dạng câu được thay thế thì ta gọi là dẫn xuất phải nhất
Ví dụ: Xét văn phạm phi ngữ cảnh G = < Σ, Δ, S, P >, trong đó P bao
gồm các luật sinh có dạng:
1.S → aAB; 2.A → bBb; 3.B→ A; 4.B→
S → aAB→ abBbB→abAbB→abbBbbB→abbbbB→abbbb (1)
S → aAB→aA→abBb→abAb→abbBbb→abbbb (2)
Trong đó (1) là đẫn xuất trái nhất, (2) là đẫn xuất phải nhất
Trang 5III CÂY DẪN XUẤT
1 Khái niệm:
Cho văn phạm phi ngữ cảnh G=<Σ, ∆, S, P> Cây suy dẫn trong văn phạm G là một cây có gốc thoả mãn năm yêu cầu sau:
- Mỗi nút có một nhãn, là một ký hiệu ∈ (Σ ∪ Δ ∪ {ε} )
- Nút gốc có nhãn là S (ký hiệu bắt đầu)
- Nếu nút trung gian có nhãn A thì A ∈ Δ
- Nếu nút n có nhãn A và các đỉnh n1, n2, , nk là con của n theo thứ
tự từ trái sang phải có nhãn lần lượt là X1, X2, , Xk thì A ⃗
X1X2 Xk là một luật sinh trong P
- Nếu nút n có nhãn là ε thì n phải là nút lá và là nút con duy nhất của nút cha của nó
Nếu đọc tất cả nhãn ở các lá theo thứ tự từ trái sang phải, ta sẽ nhận được một từ nào đó Từ đó, sẽ là một phần tử trong L(G) và được gọi là kết quả của cây suy dẫn trong G
2 Mối quan hệ giữa dẫn xuất và cây dẫn xuất
Cho một văn phạm phi ngữ cảnh G=<Σ, ∆, S, P>, một xâu w được sinh
ra bởi văn phạm Tồn tại cây dẫn xuất có kết quả là w
Như vậy: Khi cho một văn phạm phi ngữ cảnh và một xâu w được sinh ra bởi văn phạm phi ngữ cảnh đó thì ta sẽ xây dựng được cây dẫn xuất
có kết quả là xâu đó
Trang 6PHẦN HAI : CẤU TRÚC CHƯƠNG TRÌNH
I Cấu Trúc Chương Trình
1 Xử lý chuỗi nhập.
Ở đây, sử dụng các hàm để kiểm tra dữ liệu nhập vào khi nhập các luật sinh Trong bài , sử dụng 3 hàm để kiểm tra tính thích hợp của dữ liệu nhập vào Cụ thể mỗi hàm có tác dụng như sau :
- Hàm thứ 1 là : Hàm KiemTraDL(string t, string[] s) cho phép ta
sử dụng để kiểm tra xâu t có nằm trong tập xâu s hay không Cụ thể trong bài dùng để kiểm tra dữ liệu nhập vào của luật sinh, xem có thuộc tập kí hiệu phụ hay không
public static bool KiemTraDL ( string t , string [] s ) {
int ok = 0;
for ( int i = 0; i < s Length ; i ++)
if ( t == s [ i ])
{
ok = 1;
break ;
}
if ( ok == 1)
return true ;
else
return false ;
}
- Hàm thứ 2 là :KTDLSAU() để kiêm tra xâu dẫn xuất sinh ra từ kí hiệu phụ các phần tử có thuộc tập kí hiệu phụ hay bảng chữ cái hay không Áp dụng trong bài để kiểm tra việc nhập vào luật sinh có đúng các kí tự cho phép hay không Cụ thể hàm như sau :
public bool KTDLSAU ()
{
int ok1 = 1;
string s = txtsau Text ;
ttsau = new string [ s Length ];
for ( int i = 0; i < s Length ; i ++)
ttsau [ i ] = s Substring ( i , 1);
for ( int i = 0; i < ttsau Length ; i ++)
if (! KiemTraDL ( ttsau [ i ], chucai )
&& ! KiemTraDL ( ttsau [ i ], kihieuphu ))
{
ok1 = 0;
Trang 7break ;
}
if ( ok1 == 0)
return false ;
else
return true ;
}
- Hàm thứ 3 là : Hàm KT(string t) để kiểm tra 1 chuỗi t có chứa kí hiệu trong bảng kí hiệu phụ hay không Cụ thể trong bài vận dụng để kiểm tra dẫn xuất sinh bởi một kí hiệu phụ có chứa kí hiệu phụ hay không vận dụng vào để vẽ cây và tìm đẫn xuất Cụ thể hàm như sau :
public static bool KT ( string t )
{
string [] m = new string [ t Length ];
int k = 0;
for ( int i = 0; i < t Length ; i ++)
{
m [ i ] = t Substring ( i , 1);
if ( KiemTraDL ( m [ i ], kihieuphu ))
k = 1;
}
if ( k == 1)
return true ;
else
return false ;
}
2 In ra dẫn xuất.
Sau khi đã kiểm tra được sự thích hợp của dữ liệu đầu vào, thì yêu cầu của bài là in ra dẫn xuất Trong bài, có sử dụng 1 hàm xulychuoi()
để lưu các trạng thái dẫn xuất của từng kí hiệu phụ ở đây em dùng 1 mảng hai chiều để lưu Chỉ số hàng tương ứng với chỉ số của kí hiệu phụ sinh ra dẫn xuất đó, các phần tử trong cùng một hàng là các dẫn xuất được in ra từ kí hiệu phụ có chỉ số là chỉ số của hàng Cụ thể hàm xulychuoi() như sau :
public void xulychuoi ()
{
luatsinh = txtLuatSinh Text Split ( '\n' );
bdoi = new string [ kihieuphu Length , luatsinh Length - 1]; bdoi1 = new string [ kihieuphu Length , luatsinh Length - 1]; for ( int i = 0; i < luatsinh Length - 1; i ++)
Trang 8{
string [] p1 = new string [ luatsinh [ i ] Length ]; p1 = luatsinh [ i ] Split ( '-' , '>' ); for ( int m = 0; m < kihieuphu Length ; m ++) {
if ( p1 [0] == kihieuphu [ m ]) {
if ( p1 [ p1 Length - 1] != null ) bdoi [ m , i ] = p1 [ p1 Length - 1]; else bdoi [ m , i ] = null ; bdoi1 [ m , i ] = bdoi [ m , i ]; }
}
}
}
Sau đó, ta dùng những kết quả thực hiện ở các bước trên đi xây dựng giải thuật tìm ra dẫn xuất Ở đây em sử dụng dẫn xuất trái nhất, duyệt từ trái sang của chuỗi dẫn xuất nếu gặp kí tự là kí hiệu phụ thì dừng lại tìm vào mảng 2 chiều nếu như luật sinh từ kí hiệu đó khác null thì thay kí hiệu phụ đó bằng luật sinh đó Cứ thực hiện như vậy, cho tới khi nào dẫn xuất sinh ra chỉ chứa kí hiệu nằm trong bảng chữ cái thì dừng lại Cụ thể giải thuật đó được cụ thể hóa bằng đoạn mã sau: private void btnXuat_Click_1 ( object sender , EventArgs e ) {
xulychuoi (); bdoi [0, 0] = bdoi1 [0, 0] = null ; s = luatsinh [0]; string [] p2 = s Split ( '-' , '>' ); string c = p2 [ p2 Length - 1]; try {
lap : while ( KT ( c )) {
string d = null ; for ( int i = 0; i < c Length ; i ++) {
for ( int m = 0; m < bdoi GetLength (0); m ++) {
if ( Convert ToString ( c [ i ]) == kihieuphu [ m ]) {
for ( int l = 0; l < bdoi GetLength (1); l ++)
Trang 9{
if ( bdoi [ m , l ] != null ) {
string f1 = c Substring (0, i ); string f2 = bdoi [ m , l ]; string f3 = c Substring ( c IndexOf ( c [ i ]) + 1); d += f1 + f2 + f3 ; s += "->" + d ; if ( KT ( bdoi [ m , l ])) { bdoi [ m , l ] = null ; }
c = d ; goto lap ; }
else continue ; }
break ; }
else continue ; }
}
}
}
catch ( Exception ex ) {
MessageBox Show ( ex Message ); }
Form2 fr = new Form2 (); fr Show (); }
3 Vẽ cây
Sau khi đã có được dẫn xuất, yêu cầu tiếp theo là vẽ cây dẫn xuất
để vẽ được cây ta xây dựng lớp Nut, mỗi đối tượng có đầy đủ : tọa độ, màu, tên của nó chính là kí hiệu em sẽ vẽ lên nút đó, trong đó có phương thức nối để nối 2 nút với nhau dùng Line Dùng graphics để vẽ , cụ thể lớp Nut được xây dựng như sau :
Trang 10class Nut
{
public float x ;
public float y ;
public string Ten ;
public Color color ;
private Graphics myG ;
public Nut ( Graphics g )
{
myG = g ;
color = Color Red ;
}
public void Ve ()
{
myG DrawEllipse ( new Pen ( color , 2), x , y , 30, 30);
myG FillEllipse ( new SolidBrush ( Color YellowGreen ), x , y ,
30, 30);
myG DrawString ( Ten , new Font ( "Arial" , 11,
FontStyle Bold ), new SolidBrush ( color ), x + 5, y + 5);
}
public void noi ( Nut N1 , Nut N2 )
{
N1 Ve ();
N2 Ve ();
myG DrawLine ( new Pen ( color , 2), N1 x + 20, N1 y +
29, N2 x + 4, N2 y + 4);
}
}
Dùng lớp Caycon để vẽ những cây của nut trung gian và nút gốc sau đó ghép chúng lại để thành cây Cụ thể code vẽ cây con như sau :
class caycon
{
public static int sonutcon = 0;
public static Nut [] dsnut ;
public static Nut nutgoc ;
public static void ve ( string s , Graphics g , Nut t )
{
nutgoc = t ;
dsnut = new Nut [ s Length ];
for ( int i = 0; i < s Length - 1; i ++)
{
dsnut [ i ] = new Nut ( g );
dsnut [ i ] Ten = Convert ToString ( s [ i ]);
dsnut [ i ] y = nutgoc y + 70;
if ( i < ( sonutcon + 1) / 2)
Trang 11{
dsnut [ i ] x = nutgoc x - 50 * ( i );
}
else
{
dsnut [ i ] x = nutgoc x + 50 * ( i - ( sonutcon ) / 2);
}
nutgoc noi ( nutgoc , dsnut [ i ]);
}
}
}
Sử dụng lớp Nut và lớp Caycon tren để vẽ cây dẫn xuất trong lớp Vecay sử dụng dữ liêu trực tiếp từ Form Nhập Giải thuật vẽ cây được thể hiện rõ bởi đoạn mã dưới đây :
class Vecay
{
public string [] Bluatsinh = frmNhap luatsinh ;
public string [,] Bbdoi = frmNhap bdoi1 ;
public string [] KHphu = frmNhap kihieuphu ;
#region Vẽ cây
public void vecaydx ( Graphics g )
{
string chuoi1 = Bluatsinh [0];
string [] split1 = chuoi1 Split ( '-' , '>' );
Nut n1 = new Nut ( g );
string ss1 ;
int dem ;
n1 Ten = split1 [0];
n1 x = 200;
n1 y = 100;
caycon ve ( split1 [ split1 Length - 1], g , n1 );
ss1 = split1 [ split1 Length - 1];
while ( frmNhap KT ( ss1 ))
{
ss1 = "" ;
Nut [] arrnut1 = new Nut [100];
for ( int i = 0; i < caycon dsnut Length ; i ++)
{
arrnut1 [ i ] = new Nut ( g );
arrnut1 [ i ] = caycon dsnut [ i ];
}
try
{
Trang 12lap : Nut [] arrnut = arrnut1 ; dem = 0; arrnut1 = new Nut [100];
for ( int i = 0; i < arrnut Length ; i ++)
{
for ( int j = 0; j < KHphu Length ; j ++) if ( arrnut [ i ] Ten == KHphu [ j ]) {
n1 = arrnut [ i ]; for ( int k = 0; k < Bbdoi GetLength (1); k ++) {
if ( Bbdoi [ j , k ] != null ) {
caycon ve ( Bbdoi [ j , k ], g , n1 ); if ( frmNhap KT ( Bbdoi [ j , k ])) {
ss1 += Bbdoi [ j , k ]; Bbdoi [ j , k ] = null ; goto lap ; }
for ( int p = 0; p < caycon dsnut Length ; p ++) {
arrnut1 [ dem ] = new Nut ( g ); arrnut1 [ dem ] = caycon dsnut [ p ]; dem ++; }
}
} }
}
catch {
;
}
}
}
#endregion }
Trên đây là toàn bộ những đoạn mã, đoạn code chính sử dụng để thực hiện yêu cầu của bài toán