Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 26 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
26
Dung lượng
143,5 KB
Nội dung
TRƯỜNG ĐẠI HỌC KINH TẾ QUỐC DÂN BỘ MÔN CÔNG NGHỆ THÔNG TIN * * * Đề tài nghiên cứu: Phân tích từ vựng ngơn ngữ lập trình Sinh viên : Nguyễn Thị Như Quỳnh Mã SV : CQ502196 Lớp : CNTTK50 Giáo viên : Lưu Minh Tuấn Hà Nội Trong ngành khoa học máy tính, phân tích từ vựng (en:Lexical Analysis, gọi scanning lexing) trình chuyển đổi chuỗi ký tự nguồn thành chuỗi liên tiếp đoạn ký tự ngắn phân loại, gọi tokens Chương trình dùng để phân tích từ vựng gọi phân tích từ vựng (tiếng Anh Lexer) Token: Một token tập hợp xâu kí tự có nghĩa xác định, ví dụ identifier token tập hợp tất identifier Token kí hiệu kết thúc (terminal) định nghĩa văn phạm ngơn ngữ, ví dụ: Các từ khố, định danh, tố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ự loại từ ngôn ngữ học Tương tự danh từ hay tính từ, động từ, tokens định nghĩa gồm từ khóa (keyword), định danh (identifier), số nguyên, số chấm động tùy theo đặc điểm trình biên dịch Để biểu diễn tokens, người ta dùng biểu thức quy a : có xuất ký tự 'a' ab : có xuất ký tự 'b' theo sau ký tự 'a' (theo thứ tự) a|b : có 'a' có 'b' a* : xuất nhiều không xuất ký tự 'a' a+ : xuất nhiều ký tự 'a' a3 : xuất ký tự a a? : xuất a khơng xuất • Phân tích từ vựng giúp cho giai đoạn biên dịch dễ dàng hơn, ví dụ: Giai đoạn phân tích cú pháp quan tâm đến khoảng trắng lời trích loại bỏ khi phân tích từ vựng • Giảm đáng kể thời gian đọc chương trình nguồn nhóm thành token nhờ số chương trình xử lí chun dụng I Bảng chữ,phân tích từ vựng ngơn ngữ Pascal Bảng chữ 1.1 Bộ ký tự - Bộ 26 chữ Latin: Chữ in: A, B, C, , X, Y, Z Chữ thường: a, b, c, , x, y, z - Bộ chữ số thập phân: 0, 1, 2, 3, , 8, - Ký tự gạch nối dưới: _ - Các ký hiệu toán học: +, -, *, /, =, , (, ), [, } -Các ký tự khác: ; # ^ $ @ & , 1.2 Từ khóa Là từ riêng Pascal, có ngữ nghĩa xác định, khơng dùng vào việc khác đặt tên trùng với từ khóa - Từ khóa chung: PROGRAM, BEGIN, END, PROCEDURE, FUNCTION - Từ khóa để khai báo: CONST, VAR, TYPE, ARRAY, STRING, RECORD, SET, FILE, LABEL - Từ khóa lệnh lựa chọn: IF THEN ELSE, CASE OF - Từ khó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 - Từ khóa tốn tử: AND, OR, NOT, IN, DIV, MOD 1.3.Tên chuẩn Tên chuẩn tên định nghĩa sẵn Pascal, người ta định nghĩa lại muốn Trong Pascal có tên chuẩn sau đây: 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 Trong Pascal để đặt tên cho biến, hằng, kiểu, chương trình ta dùng danh hiệu (identifier) Danh hiệu Pascal bắt đầu chữ cái, sau chữ cái, chữ số dấu nối, khơng có khoảng trắng độ dài tối đa cho phép 127 Ví dụ: Sau danh hiệu: x; S1; Delta; PT_bac_2; Pascal không phân biệt chữ thường chữ hoa danh hiệu Ví dụ: aa AA một; XyZ_aBc xyZ_AbC -> Khi viết chương trình ta nên đặt danh hiệu cho chúng nói lên ý nghĩa đối tượng mà chúng biểu thị Ðiều giúp viết chương trình dễ dàng người khác dễ hiểu nội dung chương trình b Kiểu liệu Pascal có kiểu liệu 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) Từ khóa Số byte Phạm vi BYTE 0…255 SHORTINT - 128…127 INTEGER - 32768…+ 32767 WORD 0…65535 LONGINT -2147483648…2147483647 1.5.2 Kiểu số thực (real type) Từ khóa REAL Số byte SINGER DOUBLE EXTENDED 10 LONGINT Phạm vi 2.9E-39…1.7E38([2.9.10-39,1.7.1038]), 11-12 chữ số có nghĩa sau dấu phẩy 1.5E-45…3.4E38, 7-8 chữ số có nghĩa sau dấu phẩy 5.0E-324 1.7E308, 15-16 chữ số có nghĩa sau dấu phẩy 3.4E-4932…1.1E4932, 19-20 chữ số có nghĩa sau dấu phẩy - 2147483648…2147483647 1.5.3 Kiểu logic (Boolean) Một liệu thuộc kiểu BOOLEAN đại lượng chứa byte Turbo Pascal nhận hai giá trị logic TRUE (đúng) FALSE (sai) 1.5.4 Kiểu kí tự (char type) Kí tự kí hiệu bảng mã ASCII (American Standard Code for Information Interchange) Trong Turbo Pascal, nhiều kí tự liên tiếp tạo thành kiểu liệu String String có độ dài khoảng 0…255 Trong Turbo Pascal kí tự chứa byte 1.5.5 Hằng (const) Hằng số đại lượng có giá trị khơng đổi thực chương trình Một số, kí tự kiểu logic 1.5.6 Biến (Variable) Biến đại lượng có giá trị thay đổi thực chương trình Ngồi ra, Pascal cịn cho phép ta tự định nghĩa kiểu liệu từ kiểu liệu có sẵn Bộ phân tích từ vựng Hướng dẫn tạo phân tích từ vựng cho ngơn ngữ Pascal, tức chương trình đọc tệp pas in kết phân tích từ vựng hình Cách dễ dàng nhanh chóng để xây dựng phân tích từ vựng cho ngơn ngữ dùng ngôn ngữ Lex (Lexical Analyzer Generator) File Lex chứa biểu thức quy, biểu thức quy miêu tả token cụ thể ngôn ngữ, định dạng tổng quát file Lex sau: %{ //các lệnh định nghĩa viết C hay C++ %} %% //các biểu thức quy nhận dạng token %% //các đoạn code C hay C++ miêu tả ứng dụng Sau file Lex đọc file mã nguồn pascal xuất danh sách token tương ứng: %{ #include //định nghĩa biến cần dùng unsigned char ch; unsigned yline = 1; char buff[2048]; //hàm dò chuỗi thích void scan_comment() { unsigned char ch; while ((ch=input())>0 && ch != '}') if (ch == '\n') yline++; if (ch == '}') return; fprintf (stderr,"EOF duoc tim thay luc chu thich (hang %d)\n",yline); exit(1); } //hàm dò chuỗi void scan_string() { unsigned char ch, *pret; int i= 0; while ((ch=input()) >0 && ch != '\'') { if (ch == '\n') yline++; if (i >= 2047) { fprintf (stderr,"Chuoi qua dai (%d)\n",yline); exit(1); } buff[i++] = ch; } buff[i++] = 0; if (ch == '\'') return; fprintf (stderr,"EOF duoc tim thay luc chuoi (hang %d)\n",yline); exit(1); } %} %% "{" { scan_comment(); } "'" { scan_string(); printf("[string,'%s'] ",buff); } "+" { printf ("[addop] "); } "-" { printf ("[subop] "); } "*" { printf ("[mulop] "); } "/" { printf ("[divop] "); } "" { printf ("[thanop] "); } "(" { printf ("[lparent] "); } ")" { printf ("[rparent] "); } "," { printf ("[comma] "); } ";" { printf ("[pcomma] "); } ":" { printf ("[toodot] "); } ":=" { printf ("[assign] "); } "=" { printf ("[equal] "); } "." { printf ("[dot] "); } [-][0-9]+ | [0-9]+ { printf ("[iconst,%s] ", yytext); } [0-9]*[.][0-9]* | [-][0-9]*[.][0-9]* | [0-9]*[.][0-9]*[eE][-]*[0-9]+ | [-][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] "); } [a-zA-Z][a-zA-Z0-9\_]* { printf ("[ident,%s] ", yytext);} [ \t\r]* { } [\n] { printf("\n"); yline++; } { fprintf(stderr,"Syntax error: symbol '%c'(%d) o hang %d\n",yytext[0],yytext[0], yline); } %% //điểm nhập chương trình void main(int argc,char *argv[]) { //mở file mã nguồn if ((yyin = fopen(argv[1],"r")) == 0) { fprintf(stderr,"Khong the mo file %s\n",argv[1]); exit(1); } //khởi động yylex yylex_init(); //gọi yylex phân tích từ vựng yylex(); } Lưu ý đặc tả số token Pascal thường dùng, bạn dựa vào lệnh đặc tả để đặc tả thêm token lại cho đủ Sau viết xong file Lex, bạn dùng tool Lex dịch file *.c tương ứng Thí dụ hàng lệnh gọi tiện ích FLEX dịch file Lex *.c: flex -tl pascalscan.l >pascalscan.c Sau có file *.c, bạn dùng chương trình dịch C hay C++ dịch file khả thi Sau có file khả thi (thí dụ tên pascalscan.exe), bạn dùng với cú pháp sau đây: pascalscan mypro.pas để đọc file mã nguồn Pascal hiển thị token tương ứng lên hình Hoặc dùng hàng lệnh sau: pascalscan mypro.pas >output để đọc file mã nguồn Pascal xuất token tương ứng lên file "output" để tham khảo sau Lưu ý chuỗi token nhận dạng phân tích từ vựng thường gửi tới phân tích cú pháp hiển thị hay xuất file thí dụ Bạn tải tiện ích FLEX Internet (đây ứng dụng mã nguồn mở) http://download1us.softpedia.com/dl/2c924d2b8352678eb6dde18745e1e960 /4d04d70e/100120309/softwar Tôi muốn viết ứng dụng đọc hiển thị file TXT dạng Unicode Windows, hiển thị ký tự Unicode sử dụng kiểu widestring widechar Mặc dù mã Unicode chuẩn hóa tổng quát để miêu tả đồng thời nhiều ký tự nhiều ngôn ngữ, việc thực xử lý mã Unicode khơng hồn hảo, tùy vào mơi trường lập trình ngơn ngữ lập trình dùng mà mức độ hỗ trợ mã Unicode khác Thí dụ bạn dùng mơi trường Net (VC#, VJ#, VB Net) mức độ hỗ trợ mã Unicode tốt, suốt hoàn toàn với code mà bạn viết Tuy nhiên bạn dùng VB hay tệ VC++ mức độ hỗ trợ mã Unicode thấp chưa suốt cho người lập trình Thí dụ đối tượng giao diện có sẵn mơi trường VB 6.0 trở xuống hiển thị chuỗi Unicode, bạn phải dùng đối tượng tương ứng thư viện Form2 kèm theo VB Còn VC++, bạn dịch ứng dụng chế độ mặc định (ANSI) ứng dụng không xử lý chuỗi Unicode Điều kiện tiên để viết ứng dụng xử lý tốt chuỗi Unicode VC++ phải dịch ứng dụng chế độ Unicode (dùng macro dịch -D "Unicode") Về mặt lập trình VC++, bạn muốn xử lý chuỗi Unicode cấp thấp hay muốn gọi hàm API Windows để xử lý chuỗi Unicode, bạn dùng kiểu liệu widechar widestring để định nghĩa biến chứa ký tự hay chuỗi Unicode Lưu ý Windows chia tập hàm có thơng số chuỗi thành loại: loại xử lý chuỗi ANSI loại xử lý chuỗi Unicode Thí dụ hàm TextOut() hiển thị chuỗi ANSI, hàm TextOutW() hiển thị chuỗi Unicode Việc chuyển chuỗi ANSI mã Unicode thành công, ngược lại, việc chuyển chuỗi Unicode ANSI làm thông tin Sau đoạn code VC++ thực 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" vị trí (10,100), xuất chuỗi "Nguyễn Văn Hiệp" TextBox nhận dạng biến m_edit //xây dựng record miêu tả font cần dùng LOGFONT lgcursfont; // font structure lgcursfont.lfHeight = 24; lgcursfont.lfWidth = 10; lgcursfont.lfEscapement = 0; lgcursfont.lfOrientation = 0; lgcursfont.lfWeight = FW_NORMAL; lgcursfont.lfItalic = FALSE; lgcursfont.lfUnderline = FALSE; lgcursfont.lfStrikeOut = FALSE; lgcursfont.lfCharSet = ANSI_CHARSET; lgcursfont.lfOutPrecision = OUT_DEFAULT_PRECIS; lgcursfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; lgcursfont.lfQuality = DEFAULT_QUALITY; lgcursfont.lfPitchAndFamily = FF_DONTCARE; wcscpy(lgcursfont.lfFaceName, _T("Times")); //thiết lập font cho Form HDC hDC = this->GetDC()->m_hDC; HFONT hFont = ::CreateFontIndirect (&lgcursfont); ::SelectObject(hDC,hFont); //xây dựng chuỗi Unicode "Nguyễn Văn Hiệp" wchar_t buf[50]; buf[0] = 'N'; buf[1] = 'g'; buf[2] = 'u'; buf[3] = 'y'; buf[4] = 0x1ec5; buf[5] = 'n'; buf[6] = ' '; buf[7] = 'V'; buf[8] = 0x103; buf[9] = 'n'; buf[10] = ' '; buf[11] = 'H'; buf[12] = 'i'; buf[13] = 0x1ec7; buf[14] = 'p'; buf[15] = 0; //xuất chuỗi Unicode "Nguyễn Văn Hiệp" tọa độ (10,100) TextOutW(hDC,10,100,buf, wcslen(buf)); //xuất chuỗi Unicode "Nguyễn Văn Hiệp" TextBox UpdateData(TRUE); m_edit = buf; UpdateData(FALSE); II Bảng chữ phân tích từ vựng ngôn ngữ C Tập ký tự hợp lệ dùng ngơn ngữ C 1.1 Bộ kí tự - Các chữ : A, B, C , 2, a,n,c, z ( 26 chữ thường) 10 - Kiểu double : biễu diễn số thực độ xác kép Stt Kiểu Phạm vi Kích thước Char 255 byte Int -32768 32767 bytes Long -2147483648 2147484647 4bytes Unsigned 65535 bytes Float 3.4e - 38 3.4e + 38 bytes double 1.7e - 308 1.7e + 308 bytes - Kiểu void: Kiểu không giá trị, củ dùng để biểu diễn kết hàm nội dung củ pointer Kiểu nói chi tiết phần liên quan 1.5 Biến mảng : a/ Biến : Biến đại lượng thay đổi; biến có tên địa vùng nhờ danh riêng cho Khai báo biến : Cú pháp < Kiểu liệu > < Danh sách biến >; Ví dụ : Int i,j ; long cucdai; double tongsothue; Int a,b = 20; float e = 35.1; x=30.5; b/ Mảng: tập hợp phần tử có kiểu chung tên Khai báo : Ví dụ : Int Mang1[ 10 ]; Float Bang [10][10]; -Mảng chiều : dãy ký tự phần tử nhớ, phần tử chiếm số byte tương ứng với kiểu - Mảng nhiều chiều : Gồm phần tử liên tiếp từ hàng sang hàng Các số đánh số từ trở Ví dụ : - Mãng 1[0] Mãng1[9] - Bang[][] Bang[2][0] Bang[1][9] Bang[9][0] Bang[9][9] * Chú ý : &Mang1[3] &Bang[2][5]sai ( Ðúng chiều sai 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 cách thêm tiền tố Ox theo số cách thêm tiền tố O ( Octal = bát phân ) * Ví dụ : O306 viết theo số : Giá trị = * + 3* * = 198 hệ 10 12 O345 = 3*8*8 + 4*8 + = 229 Ox147 = 1*16*16 + 4*16 +7 =327 hệ 10 OxAa= 10*16+13=173 - Lý a A =10 b B =11 c C =12 d D =13 e E = 14 f F = 15 b/Hằng long ( long Int : nguyên lớn ) : giống nguyên, khác thêm L l đầu * Ví dụ : 180L, 123456789l ( Hằng nguyên giá trị vượt số nguyên nguyên lớn (long) c/Hằng thực ( float double ) : Có cách viết - Cách : ( dạng thập phân) Số gồm : phần nguyên, dấu chấm thập phân phần phân * Ví dụ : 214.35 , - 234.34 - Cách : Viết theo dạng khoa học * Ví dụ : 1.543e7 = 15430000 123.456E-4 = 0.123456 ( 123.456/105) d/Hằng ký tự : Viết dấu nháy đơn Giá trị mã ASCII chữ * Ví dụ : 'A' = 65; 'd' = 100, '9 ' - '0 ' = 57 - 48 = - Hằng ký tự cịn viết \X1X2X3 , \x1x2x3 : x1,x2,x3 số nguyên hệ *Ví dụ : chữ a mã hệ 10 97 đổi hệ O141 => \141='a'; \ 101='A'; \ 142 ='b' * Một số đặc biệt viết theo qui ước sau : Viết Ký tự Diễn giải ' \ " ' dấu nháy đơn ' \" ' " dấu nháy kép ' \\ ' \ dấu chéo ngược '\n ' \n ký tự xuống dòng ' \0 ' \0 ký tự rỗng ( null) Chú ý : - Phân biệt ký tự '0 ' ' \0 ' Hằng ' ' với chữ số có mã = 48 - Hằng '\0 ' với ký tự \0 (null) có mã 13 - Hằng ký tự thực số nguyên => dùng số nguyên hệ 10 đê biểu diễn ký tự * Ví dụ : printf( " %c%c", 65,66) in AB e/Hằng xâu ký tự : đặt dấu nháy kép ( " ") Hằng lưu trữ mãng ký tự mà ký tự cuối rỗng (null) ' \0 ' Ví dụ : "Lơp Hoc" - Hằng đinh nghĩa toán tử define + Cú pháp : # define < tên > < giá trị> Trong chương trình biến max thay đổi giá trị 100 Ví dụ : # define MAX 100 # Define pi 3.141593 1.7 Phép toán : + Phép toán số học gồm : +,-,*, / ( Phép chia lấy phần nguyên ), % ( phép chia lấy phần dư) + Phép toán quan hệ : , =, = =, ! = ( khác) + Phép toán logic : || ( ) , && ( và) ! ( not ), #0 hay =1 : True( đúng) ; =0 : Falsse ( sai) + Phép toán tăng giảm : ++ cộng thêm vào toán hạng * Ví dụ : Int n=10; n++;=> n=11 n=n+1; Chú ý : - n++ : giá trị n lấy trước tăng n - ++n : giá trị n lấy sau tăng n - tương tự n , n ; + Toán tử thao tác bit : Không áp dụng cho kiểu float double & : phép hội bít ( và) | : phép tuyển bit ( hoặc) ^ : phép tuyển bit loại trừ > : phép dịch phải : phép lấy phần bù Ví dụ : 105 & = /* 0111 1001 & 0000 0111 = 0000 0001 */ 105 | 17 = 127 /* 0111 1001 | 0000 0111 = 0111.1111 */ 0x60 = 0x96 /* 0110 1001 = 1001 0110 */ + Toán tử chuyển đổi kiểu : ta dùng tốnt chuyển kiểu để chuyển kiểu sang kiểu mong muốn 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 14 - Chú ý : + Một số kiểu float chuyển sang kiểu Int bị chặt cụt phần thập phân + Một số kiểu long chuyển sang kiểu Int cắt bỏ vài chữ số * Ví dụ : n = 2560.70 (int)n = 2560 + Toán tử gán : - Cú pháp : < biến> = < biểu thức> * Ví dụ : c = a + b ; d= t + ; i= i+2 (Viết gọn i+=2; ) i= i*2 (i*=2; ) x = x >> (x >> = 1;) Chú ý : Các phép tốn C có độ ưu tiên khác quy tắc kết hợp khác => Bảng liệt kê phép toán theo thứ tự ưu tiên từ xuống dưới, phép tốn dịng có thứ tự Phép tố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 : xây dựng toán tử , toán hạng hằng, biến, hàm - Biểu thức gán : Ví dụ : A = B =C =5 => A=5, B = 5, C = - Biểu thức điều kiện có dạng : B1?E1 : E2 : Nếu B giá trị biểu thức = E1 ngược lại E2 * Ví dụ : S=x>y ? x:y cho giá trị lớn x y Bộ phân tích từ vựng ngơn ngữ C 15 #include "stdio.h" #include "iostream.h" #include "conio.h" #include "string.h" #include "ctype.h" #include "assert.h" #include "stdlib.h" //////////////////////////////////////////////////////// #define ERROR #define LPAR #define RPAR #define PLUS #define MINUS #define STAR #define DIV #define MOD #define SLASH #define ID #define NUM 10 #define DONE 11 const char* Lexemes[]={"ERROR","LPAR","RPAR","PLUS","MINUS","STAR","DIV ", "MOD","SLASH","ID","NUM","DONE"}; const char* ErrorType[]={"'&' expected","'|' expected","Token Too Long", "SymTable OverFlow","Unknown Character"}; //////////////////////////////////////////////////////// #define LexerMax 100 //LexerMax Phai >=4 #define TokenMax 40 //TokenMax 0)&&(i