Tải bản đầy đủ (.pdf) (5 trang)

Tài liệu Hướng dẫn tạo bộ phân tích từ vựng cho ngôn ngữ Pascal pptx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (117.98 KB, 5 trang )

Hướng dẫn tạo bộ phân tích từ vựng cho ngôn ngữ Pascal

Xin 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). File
Lex 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++
%}
%%
//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 token tương ứng:
%{
#include <stdlib.h>
//định nghĩa các biến cần dùng
unsigned char ch;
unsigned yline = 1;
char buff[2048];
//hàm dò chuỗi chú 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 trong luc do chu thich (hang %d)\n",yline);


exit(1);
}

//hàm dò hằng 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 trong luc do chuoi (hang %d)\n",yline);
exit(1);
}
%}
%%
"{" { scan_comment(); }
"'" { scan_string();
printf("[string,'%s'] ",buff); }
"+" { printf ("[addop] "); }
"-" { printf ("[subop] "); }
"*" { printf ("[mulop] "); }
"/" { printf ("[divop] "); }
"<" { printf ("[lessop] "); }

">" { 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 của 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 ý rằng chúng tôi chỉ đặc tả một số token Pascal thường dùng, bạn dựa vào các lệnh đặc tả
để đặc tả thêm các token còn lại cho đủ.

Sau khi đã viết xong file Lex, bạn có thể dùng tool Lex dịch nó ra file *.c tương ứng. Thí dụ
dưới đây là hàng lệnh gọi tiện ích FLEX dịch file Lex ra *.c:
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.

Bạn có thể tải tiện ích FLEX trên Internet (đây là ứng dụng mã nguồn mở).

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
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" ra tọa độ (10,100)
TextOutW(hDC,10,100,buf, wcslen(buf));
//xuất chuỗi Unicode "Nguyễn Văn Hiệp" ra TextBox
UpdateData(TRUE);
m_edit = buf;
UpdateData(FALSE);
 

×