Trong ngành khoa học máy tính, phân tích từ vựng en:Lexical Analysis, còn được gọi là scanning hoặc lexing là một quá trình chuyển đổi chuỗi ký tự nguồn thành một chuỗi liên tiếp các đoạ
Trang 1TRƯỜNG ĐẠI HỌC KINH TẾ QUỐC DÂN
BỘ MÔN CÔNG NGHỆ THÔNG TIN
Trang 2
Trong ngành khoa học máy tính, phân tích từ vựng (en:Lexical Analysis,
còn được gọi là scanning hoặc lexing) là một quá trình chuyển đổi chuỗi ký
tự nguồn thành một chuỗi liên tiếp các đoạn ký tự ngắn hơn đã được phân
loại, gọi là tokens Chương trình dùng để phân tích từ vựng được gọi là bộ phân tích từ vựng (tiếng Anh là Lexer).
Token: Một token là một tập hợp các xâu kí tự có một nghĩa xác định,
ví dụ identifier token là tập hợp tất cả các identifier Token chính là các
kí hiệu kết thúc (terminal) trong định nghĩa văn phạm của một ngôn ngữ,
ví dụ: Các từ khoá, định danh, toán tử, hằng, xâu kí tự, dấu ngoặc đơn,dấu phẩy, dấu chấm phẩy
Tokens tương tự như loại từ trong ngôn ngữ học Tương tự như danh từ hay tính từ, động từ, tokens sẽ được định nghĩa gồm từ khóa (keyword), địnhdanh (identifier), số nguyên, số chấm động tùy theo đặc điểm của trình biên dịch
Để biểu diễn các tokens, người ta dùng biểu thức chính quy
a : có xuất hiện ký tự 'a'
ab : có xuất hiện ký tự 'b' theo sau ký tự 'a' (theo đúng thứ tự)
a|b : có 'a' hoặc có 'b'
a* : xuất hiện nhiều hoặc không xuất hiện ký tự 'a'
a+ : xuất hiện nhiều hoặc ít nhất là một ký tự 'a'
a3 : xuất hiện 3 ký tự a
a? : xuất hiện a hoặc không xuất hiện
• Phân tích từ vựng giúp cho các giai đoạn biên dịch tiếp theo dễ dàng hơn, ví dụ: Giai đoạn phân tích cú pháp không phải quan tâm đến các khoảng trắng cũng như các lời chú trích vì nó đã được loại bỏ khi khi phân tích từ vựng
• Giảm đáng kể thời gian đọc chương trình nguồn và nhóm thành các token nhờ một số chương trình xử lí chuyên dụng
I Bảng chữ,phân tích từ vựng của ngôn ngữ Pascal
1 Bảng chữ
1.1 Bộ ký tự
Trang 3PROGRAM, BEGIN, END, PROCEDURE, FUNCTION
- Từ khóa để khai báo:
CONST, VAR, TYPE, ARRAY, STRING, RECORD, SET, FILE, LABEL
- Từ khóa của lệnh lựa chọn:
IF THEN ELSE, CASE OF
- Từ khóa của lệnh lặp:
FOR TO DO, FOR DOWNTO DO, WHILE DO,
REPEAT UNTIL
- Từ khóa điều khiển:
WITH, GOTO, EXIT, HALT
Boolean, Char, Integer, Word, Byte, Real, Text
False, True, MaxInt
Abs, Arctan, Chr, Cos, Sin, Eof, Eoln
Exp, Ln, Odd, Ord
Round, Trunc, Sqr, Pred, Succ
Dispose, New, Get, Put, Read, Readln,
Write, Writeln Reset, Rewrite
a Danh hiệu tự đặt
Trang 4Trong Pascal để đặt tên cho các biến, hằng, kiểu, chương trình con ta
dùng các danh hiệu (identifier) Danh hiệu của Pascal được bắt đầu bằng một
chữ cái, sau đó có thể là các chữ cái, chữ số hay là dấu nối, không được có
khoảng trắng và độ dài tối đa cho phép là 127
Ví dụ: Sau đây là các danh hiệu: x; S1; Delta; PT_bac_2;
Pascal không phân biệt chữ thường và chữ hoa trong một danh hiệu
Ví dụ: aa và AA là một; XyZ_aBc và xyZ_AbC là một
-> Khi viết chương trình ta nên đặt các danh hiệu sao cho chúng nói lên
các ý nghĩa của đối tượng mà chúng biểu thị Ðiều này giúp chúng ta viết
chương trình dễ dàng và người khác cũng dễ hiểu nội dung chương trình
b Kiểu dữ liệu
Pascal có 4 kiểu dữ liệu cơ bản:
Integer : kiểu số nguyên
Real : kiểu số thực
Char : kiểu kí tự
Boolean : kiểu logic
1.5.1 Kiểu số nguyên (integer type)
có nghĩa sau dấu phẩy
SINGER 4 1.5E-45…3.4E38, 7-8 chữ số có nghĩa sau dấu phẩy.DOUBLE 8 5.0E-324 1.7E308, 15-16 chữ số có nghĩa sau dấu
phẩy
EXTENDED 10 3.4E-4932…1.1E4932, 19-20 chữ số có nghĩa sau dấu
phẩy
Trang 51.5.3 Kiểu logic (Boolean)
Một dữ liệu thuộc kiểu BOOLEAN là một đại lượng được chứa trong 1 byte ở Turbo Pascal và chỉ có thể nhận được một trong hai giá trị logic là TRUE (đúng) và FALSE (sai)
1.5.4 Kiểu kí tự (char type)
Kí tự là một trong các kí hiệu trong bảng mã ASCII (American StandardCode for Information Interchange) Trong Turbo Pascal, nhiều kí tự liên tiếp tạo thành một kiểu dữ liệu mới là String String có độ dài trong khoảng 0…255
Trong Turbo Pascal mỗi kí tự được chứa trong 1 byte
2 Bộ phân tích từ vựng
Hướng dẫn tạo bộ phân tích từ vựng cho ngôn ngữ Pascal, tức là chương trình đọc tệp pas và in kết quả phân tích từ vựng ra màn hình
Cách dễ dàng và nhanh chóng nhất để xây dựng bộ phân tích từ vựng cho
1 ngôn ngữ nào đó là dùng ngôn ngữ Lex (Lexical Analyzer Generator) FileLex chứa các biểu thức chính quy, mỗi biểu thức chính quy miêu tả 1 token
cụ thể của ngôn ngữ, định dạng tổng quát của file Lex như sau:
%{
//các lệnh định nghĩa viết bằng C hay C++
%}
Trang 6%%
//các biểu thức chính quy nhận dạng các token
%%
//các đoạn code C hay C++ miêu tả ứng dụng
Sau đây là file Lex đọc file mã nguồn pascal rồi xuất ra danh sách các tokentương ứng:
Trang 7[-][0-9]*[.][0-9]*[eE][-]*[0-9]+ { printf ("[rconst,%s] ", yytext); }
[pP][rR][oO][gG][rR][aA][mM] { printf ("[program] "); }
[uU][sS][eE][sS] { printf ("[uses] "); }
[vV][aA][rR] { printf ("[var] "); }
[tT][yY][pP][eE] { printf ("[type] "); }
[bB][eE][gG][iI][nN] { printf ("[begin] "); }
[eE][nN][dD] { printf ("[end] "); }
[fF][uU][nN][cC][tT][iI][oO][nN] { printf ("[function] "); }
[pP][rR][oO][cC][eE][dD][uU][rR][eE] { printf ("[procedure] "); }
[iI][fF] { printf ("[if] "); }
[tT][hH][eE][nN] { printf ("[then] "); }
[eE][lL][sS][eE] { printf ("[else] "); }
[dD][oO] { printf ("[do] "); }
[rR][eE][pP][eE][aA][tT] { printf ("[repeat] "); }
[uU][nN][tT][iI][lL] { printf ("[until] "); }
Trang 8[a-zA-Z][a-zA-Z0-9\_]* { printf ("[ident,%s] ", yytext);}
//điểm nhập của chương trình
void main(int argc,char *argv[]) {
flex -tl pascalscan.l >pascalscan.c
Sau khi đã có file *.c, bạn có thể dùng chương trình dịch C hay C++ dịch nó
ra file khả thi Sau khi có file khả thi (thí dụ tên là pascalscan.exe), bạn có thể dùng nó với cú pháp sau đây:
pascalscan mypro.pas để đọc file mã nguồn Pascal rồi hiển thị các token tương ứng lên màn hình Hoặc dùng hàng lệnh sau:
pascalscan mypro.pas >output để đọc file mã nguồn Pascal rồi xuất các token tương ứng lên file "output" để tham khảo sau đó
Lưu ý rằng chuỗi token nhận dạng được bởi bộ phân tích từ vựng thường được gửi tới bộ phân tích cú pháp chứ ít ai hiển thị hay xuất ra file như thí
dụ trên
Trang 9Bạn có thể tải tiện ích FLEX trên Internet (đây là ứng dụng mã nguồn mở).
http://download1us.softpedia.com/dl/
2c924d2b8352678eb6dde18745e1e960/4d04d70e/100120309/softwar
Tôi muốn viết một ứng dụng đọc và hiển thị file TXT dạng Unicode trên Windows, nhưng tôi không thể hiển thị đúng các ký tự Unicode mặc dù đã
sử dụng kiểu widestring và widechar
Mặc dù mã Unicode đã được chuẩn hóa và tổng quát để miêu tả đồng thời nhiều ký tự của nhiều ngôn ngữ, nhưng hiện nay việc hiện thực xử lý mã Unicode không hoàn hảo, tùy vào môi trường lập trình và ngôn ngữ lập trìnhđược dùng mà mức độ hỗ trợ mã Unicode rất khác nhau Thí dụ nếu bạn dùng môi trường Net (VC#, VJ#, VB Net) thì mức độ hỗ trợ mã Unicode làrất tốt, hầu như trong suốt hoàn toàn với code mà bạn viết Tuy nhiên nếu bạn dùng VB hay tệ hơn là VC++ thì mức độ hỗ trợ mã Unicode còn khá thấp và chưa được trong suốt cho người lập trình Thí dụ các đối tượng giao diện có sẵn của môi trường VB 6.0 trở xuống không thể hiển thị đúng được chuỗi Unicode, bạn phải dùng các đối tượng tương ứng trong thư viện
Form2 kèm theo VB Còn trong VC++, nếu bạn dịch ứng dụng ở chế độ mặcđịnh (ANSI) thì ứng dụng sẽ không xử lý được chuỗi Unicode Điều kiện tiên quyết để viết ứng dụng xử lý tốt chuỗi Unicode trong VC++ là phải dịchứng dụng ở chế độ Unicode (dùng macro dịch là -D "Unicode") Về mặt lập trình VC++, nếu bạn muốn xử lý chuỗi Unicode cấp thấp hay muốn gọi các hàm API Windows để xử lý chuỗi Unicode, bạn sẽ dùng kiểu dữ liệu
widechar và widestring để định nghĩa các biến chứa ký tự hay chuỗi
Unicode Lưu ý rằng Windows chia tập các hàm có thông số chuỗi ra thành
2 loại: loại chỉ xử lý chuỗi ANSI và loại chỉ xử lý chuỗi Unicode Thí dụ hàm TextOut() chỉ hiển thị chuỗi ANSI, còn hàm TextOutW() chỉ hiển thị chuỗi Unicode Việc chuyển chuỗi ANSI về mã Unicode luôn thành công, nhưng ngược lại, việc chuyển chuỗi Unicode về ANSI có thể làm mất thông tin
Sau đây là đoạn code VC++ thực hiện việc thiết lập font hỗ trợ Unicode cho Form, gọi hàm API TextOutW() để xuất chuỗi Unicode "Nguyễn Văn Hiệp" ra vị trí (10,100), xuất chuỗi "Nguyễn Văn Hiệp" ra TextBox được nhận dạng bởi biến m_edit
//xây dựng record miêu tả font cần dùng
LOGFONT lgcursfont; // font structure
Trang 10buf[2] = 'u'; buf[3] = 'y';
buf[4] = 0x1ec5; buf[5] = 'n';
Trang 11- Các chữ số : 0,1, , 9.
- Ký tự gạch nối _ ( chú ý phân biệt dấu - )
- Dấu cách ( space) : dùng để phân biệt các từ :
Ví dụ : lop Học( 7 kí tự) - LopHoc( 6 kí tự)
1.2 Tên
Tên ( định danh ) : là 1 dãy kí tự bắt đầu bằng chữ hoặc ký tự gạch
dưới, theo sau là chữ cái, chữ số hoặc ký tự gạch nối (-)
- Tên : dùng làm tên hằnp, tên biến , nhãn , tên hàm
Ví dụ : Tên đúng : _abc, Delta_1, BETA
Tên sai : 1xyz ( vì bắt đầu là 1 chữ số )
trong C gồm : Break, char, continue, case, do, double, default, else,
float, for, goto, int,if, long, return, struct, switch, unsigned,
while, typedef, union voi, volatile,
1.4 Các kiểu dữ liệu cơ bản trong C : 4 kiểu : char, Int, float, double.
- Kiểu char ( 1 byte ) : biễu diễn 1 ký tự thuộc ASCII ( thực chất là số
- Kiểu Int : 3 loại : Int, long Int ( long ) và unsigned Int ( unsigned)
- Kiểu Float : biểu diễn các số thực độ chính xác định
Trang 12- Kiểu double : biễu diễn các số thực độ chính xác kép.
5 Float 3.4e - 38 3.4e + 38 4 bytes
6 double 1.7e - 308 1.7e + 308 8 bytes
- Kiểu void: Kiểu không giá trị, củ dùng để biểu diễn kết quả hàm
cũng như nội dung củ pointer Kiểu này sẽ nói chi tiết ở các phần liên
Int a,b = 20; float e = 35.1; x=30.5;
b/ Mảng: là tập hợp các phần tử có cùng 1 kiểu và chung 1 tên
* Chú ý : &Mang1[3] đúng nhưng &Bang[2][5]sai ( Ðúng đối với 1 chiều
và sai đối với nhiều chiều)
1.6 Hằng : Ðại lượng không thay đổi
a/ Hằng nguyên ( Int ): có giá trị từ -32768 đến 32767
- Có thể viết theo hệ 16 bằng cách thêm tiền tố Ox hoặc theo cơ số 8 bằng cách thêm tiền tố O ( Octal = bát phân )
* Ví dụ : O306 viết theo cơ số 8 : Giá trị = 6 * 8 0 + 3* 8 * 8 = 198 trong hệ10
Trang 13c/Hằng thực ( float và double ) : Có 2 cách viết
- Cách 1 : ( dạng thập phân) Số gồm : phần nguyên, dấu chấm thập phân và phần phân
*Ví dụ : chữ a mã hệ 10 là 97 đổi ra hệ 8 là O141 => \141='a';
\ 101='A';
\ 142 ='b'
* Một số hằng đặc biệt được viết theo qui ước như sau :
Viết Ký tự Diễn giải
' \ " ' dấu nháy đơn
Trang 14- Hằng ký tự thực sự là số nguyên => có thể dùng số nguyên hệ 10 đê biểu diễn ký tự
- Hằng có thể được đinh nghĩa đối với toán tử define
+ Cú pháp : # define < tên hằng > < giá trị>
Trong chương trình mọi biến max đều được thay đổi giá trị 100
Chú ý : - n++ : giá trị n được lấy trước khi tăng n
- ++n : giá trị n được lấy sau khi tăng n
- tương tự n , n ;
+ Toán tử thao tác bit : Không áp dụng cho kiểu float hoặc double
& : phép hội các bít ( và)
| : phép tuyển các bit ( hoặc)
^ : phép tuyển các bit loại trừ
Toán tử chuyển đổi kiểu : ta có thể dùng toánt ử chuyển kiểu để chuyển
1 kiểu bất kỳ sang kiểu mong muốn bằng cách dùng toán tử sắc thái (
cast) theo quy tắc sau :
ép Kiểu ( type cast ) : ( kiểu ) Biến Kiểu mong muốn
* Ví dụ : int i = 10
ă ( float ) i => 10.0
Trang 15- Chú ý : + Một số kiểu float khi chuyển sang kiểu Int sẽ bị chặt cụt phần thập phân.
+ Một số kiểu long khi chuyển sang kiểu Int sẽ cắt bỏ vài chữ số
ý : Các phép toán trong C có độ ưu tiên khác nhau và quy tắc kết hợp
khác nhau => Bảng liệt kê các phép toán theo thứ tự ưu tiên từ trên
xuống dưới, các phép toán trên dòng có thứ tự như nhau
Phép toán Trình tự kết hợp
(),[ ], ă trái qua phải
|, dấu ngã, &*, - -, + + , ( type ) size of phải qua trái
*,/, % trái qua phải
+, - trái qua phải
<< ,>> trái qua phải
<,<= ,> ,>= trái qua phải
& trái qua phải
| trái qua phải
&& trái qua phải
|| trái qua phải
? phải qua trái
= =, !=, +=, -= phải qua trái
1.8 Biểu thức : được xây dựng bằng các toán tử , toán hạng là các hằng,
biến, hàm
- Biểu thức gán : Ví dụ : A = B =C =5 => A=5, B = 5, C = 5
- Biểu thức điều kiện có dạng : B1?E1 : E2 : Nếu B 1 đúng giá trị biểu thức
= E1 ngược lại E2
* Ví dụ : S=x>y ? x:y cho giá trị lớn nhất của x và y
2 Bộ phân tích từ vựng ngôn ngữ C
Trang 16const char* ErrorType[]={"'&' expected","'|' expected","Token Too Long",
"SymTable OverFlow","Unknown Character"};
Trang 17int flag;//flag=0 nghia la da do vao nen khong do lai.
int testlength();//tra ve true neu token dai qua gioi han
int fail(int);//co kem theo dieu kien de bat co flag
void retract(int i);//co kem theo dieu kien de bat co flag
void update();//co xet flag de xem co do vao khong
int lookup(char const *s);
int insert(char const *s,int type);
int gettoken(int i);
void display();
void save();
};
Trang 18if (( p1<=LexerMax/2-1 && p2>LexerMax/2-1 )||
( p1 >LexerMax/2-1 && p2<LexerMax/2-1 ))
flag=0;
p2=p1;
if (i== 1) return(10);else
if (i==10) return(13);else
Trang 25int main(int n, char *arg[])