Mô Tả Ngôn Ngữ Lập Trình Và Viết Chương Trình Xây Dựng Cây Phân Tích Cú Pháp

36 1.1K 2
Mô Tả Ngôn Ngữ Lập Trình Và Viết Chương Trình Xây Dựng Cây Phân Tích Cú Pháp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

ĐẠI HỌC QUỐC GIA THÀNH PHỐ HỒ CHÍ MINH CHƢƠNG TRÌNH ĐÀO TẠO THẠC SĨ CNTT QUA MẠNG -  - Mô Tả Ngôn Ngữ Lập Trình Và Viết Chƣơng Trình Xây Dựng Cây Phân Tích Cú Pháp Bộ môn : Nguyên Lý Ngôn Ngữ LT GVHD : TS Nguyễn Tuấn Đăng Thực : Nguyễn Khánh Ngọc CH1001117 Thành phố Hồ Chí Minh - Tháng Năm 2012 NHẬN XÉT CỦA GIẢNG VIÊN HƢỚNG DẪN MỤC LỤC Phần 1: Tìm hiểu văn phạm phân tích cú pháp I Khái niệm ngôn ngữ lập trình II Văn phạm cú pháp 1 Văn phạm phi ngữ cảnh (Context-Free Grammar) a BNF (Backus Naur normal form) b Dẫn xuất ngôn ngữ c Cây dẫn xuất d Sự mơ hồ (Ambiguity) Ràng buộc cú pháp theo ngữ cảnh 11 III Trình Biên Dịch 12 Phân tích từ vựng (lexical analysis) 13 Phân tích cú pháp (syntax analysis) 14 Phân tích ngữ nghĩa (semantic analysis) 15 Phát sinh dạng trung gian (Generation of intermediate forms) 15 Tối ưu hóa mã lệnh (Code optimisation) 16 Sản sinh mã lệnh (Code generation) 16 IV Ngữ nghĩa 16 Trạng thái (State) 17 Quá trình chuyển đổi (Transition) 18 Ngữ nghĩa biểu thức (Expression semantics) 19 Ngữ nghĩa lệnh (Command semantics) 20 Tính Toán (Computations) 21 V Ngữ Dụng Và Cài Đặt 21 Phần 2: Xây Dựng Trình Phân Tích Cú Pháp I Định nghĩa văn phạm 23 II Xây dựng trình phân tích cú pháp C # 24 Định nghĩa token phương thức làm việc token 24 Xây dựng trình phân tích cú pháp (parser) C # 24 Scanner 26 Hàm Main chương trình minh họa 30 Tài liệu tham khảo 32 Phần I: Tìm hiểu văn phạm trình phân tích cú pháp I Khái niệm ngôn ngữ lập trình Một ngôn ngữ lập trình dạng hình thức nhân tạo mà thuật giải diễn đạt hình thức Việc nghiên cứu ngôn ngữ lập trình sử dụng tốt nhiều khái niệm công cụ phát kỷ qua ngôn ngữ học(lĩnh vực ngôn ngữ học nghiên cứu ngôn ngữ tự nhiên ngôn ngữ nhân tạo) Không sâu vào chi tiết ngôn ngữ học, tiểu luận đưa vấn đề đê mô tả ngôn ngữ lập trình công cụ sử dụng để xây mô tả ngôn ngữ lập trình Những cấp độ mô tả Trong việc nghiên cứu ngôn ngữ học cổ điển, Morris nghiên cứu cập độ khác để mô tả ngôn ngữ Ông ta định nghĩa cấp độ chính: grammar (ngữ pháp), semantic ( ngữ nghĩa) pragmatics ( thực dụng )  Grammar ( văn phạm ) phần việc mô tả ngôn ngữ, trả lời câu hỏi: cụm từ diễn đạt chưa? Khi bảng ký tự (alphabet) ngôn ngữ định nghĩa, thành phần từ vựng cấu thành từ chuỗi có trình tự ký hiệu ngôn ngữ định nghĩa Khi bảng ký tự alphabet từ vựng định nghĩa, cú pháp (syntax) mô tả thứ tự từ cấu thành cụm từ hợp lệ  Semantics ( ngữ nghĩa ) phần mô tả ngôn ngữ, trả lời câu hỏi: “cụm từ nghĩa gì?” Ngữ nghĩa để ý nghĩa cụm từ Đối với ngôn ngữ tự nhiên, xử lý ngữ nghĩa phức tạp, ngôn ngữ nhân tạo thi đơn giản nhiều Trong trường hợp ngữ nghĩa mối quan hệ câu ý nghĩa chúng  Pragmatics (Thực dụng) phần mô tả ngôn ngữ, tự hỏi “Chúng ta sử dụng câu có ý nghĩa nào?” Những câu có ý nghĩa sử dụng theo nhiều cách khác tùy vào người sử dụng  Trong trường hợp ngôn ngữ lập trình thêm cấp độ thứ cấp độ thực thi (implementation) Giả sử quan tâm ngôn ngữ thủ tục hàm, mô tả “Làm để thực thi câu theo ngữ nghĩa câu” Chúng ta xem xét ngôn ngữ tự nhiên đễ diễn tả công thức nấu ăn Cú pháp diễn tả câu dùng để diễn đạt công thức nấu ăn Ngữ nghĩa giải thích công thức nấu ăn Pragmatic (thực dụng) mô tả người đầu bếp diễn dịch công thức Và cuối implementation ( thực thi) mô tả cách thực công thức nâu ăn, chuẩn bị chén đĩa thành ăn theo ngữ nghĩa muốn trình bày Trang II Văn phạm cú pháp Văn phạm (grammar) ngôn ngữ xây dựng bảng ký tự alphabet từ vựng Sau cú pháp (syntax) định nghĩa chuỗi ký tự theo câu cụm từ có định dạng chuẩn Vào năm 1950 nhà ngôn ngữ học người Mỹ Noam Chomsky đưa kỹ thuật mô tả cú pháp, mô tả sử dụng hình thức thiết kế đặc biệt để giới hạn mơ hồ ngôn ngữ tự nhiên Những kỹ thuật gọi ngữ pháp sản sinh, chúng không sử dụng nhiều việc mô tả ngôn ngữ tự nhiên ( ngôn ngữ tự nhiên phức tạp ) mà dùng để mô tả cú pháp ngôn ngữ lập trình Ví dụ: mô tả ngôn ngữ đơn giản Đó ngôn ngữ chuỗi đối xứng, cấu thành ký tự a b Chúng ta có bảng ký tự (alphabet) sau A={a,b}, ta chọn chuỗi câu thành từ ký tự A, để tạo thành chuỗi đối xứng Cách đơn giản để thực điều này, ý có đệ quy đơn giản chuỗi đối xứng Chúng ta phát biểu a b chuỗi đối xứng, s là chuỗi đối xứng asa bsb chuỗi đối xứng Các chuỗi đối xứng có chiều dài số lẻ Nhưng chiều dài chuỗi đối xứng số chẵn, ví dụ abba Trong trường hợp ta thêm sư kiện chuỗi rỗng (empty string) chuỗi đối xứng Như chuỗi gọi la đối xứng (ví dụ: aabaa abba ), tồn chuỗi ký tự ghép vào theo nguyên tắc quy nạp Văn phạm phi ngữ cảnh Văn phạm phi ngữ cảnh ký hiệu để diễn đạt ngắn gọn, súc tích xác định nghĩa đệ quy chuỗi chuỗi chung ta thấy ví dụ chuỗi đối xứng Một định nghĩa quy nạp chuỗi đối xứng diễn tả theo hình thức văn phạm sau: P → P→a P→b P → aPa P → bPb Theo luật P chuỗi đối xứng, mũi tên → nghĩa “có thể là” Ba dòng trường hợp định nghĩa quy nạp, hai dòng cuối bước Trang quy nạp Ví dụ cho thấy văn phạm phi ngữ cảnh công cụ đê mô tả ngôn ngữ lập trình Văn phạm phi ngữ cảnh công cụ để mô tả ngôn ngữ lập trình Các ký hiệu thuật ngữ văn phạm phi ngữ cảnh sau Có tập hữu hạn A, gọi bảng chữ cái, A* tập tất chuỗi hữu hạn A Chúng ta thấy rằng, thông qua định nghĩa chuỗi rỗng thuộc A* , ký hiệu 𝜖 Một ngôn ngữ thức dựa bảng chử A tập A* Một văn phạm thức để nhận dạng tập chuỗi dựa bảng ký tự cho Định nghĩa 2.1 (Context-Free Grammar): Một văn phạm phi ngữ cảnh tứ gồm (NT,T,R,S) Trong đó:  NT tập hữu hạn ký hiệu ( non-terminal symbols, variables, syntatic categories)  T tập hữu hạn ký hiệu (terminal symbols)  R tập hữu hạn luật, luật diễn đạt theo hình thức sau 𝑽→𝝎 V (vế trái luật) ký hiệu non-terminal đơn giản, 𝜔 ( vế phải luật ) chuỗi rỗng terminal symbol hay non-terminal symbol (𝑇 ∪ 𝑁𝑇)  S phần tử NT, phần tử khởi tạo Qua ví dụ này, chuỗi đối xứng ta có văn phạm biễu diễn chuỗi đối xứng tứ gồm ({P},{a,b},R,P) với R tập luật sau : P→ P→a Chúng ta thấy luật có vế phải rỗng, ký hiệu null(chuoi64 rỗng ∈) Ví dụ 1: Một ví dụ văn phạm đơn giản mô tả biểu thức toán học ( dựa toán tử +,*,-, toán tử hai ) Những phần tử nhỏ biểu thức định danh đơn giản định dạng từ chuỗi hữu hạn ký hiệu a b Trang Chúng ta định nghĩa văn phạm 𝑮 = 𝑬, 𝑰 , 𝒂, 𝒃, +, −, , , 𝑹, 𝑬 , với R tập luật sau E → I E → E + E E → E ∗ E E → E − E E → −E E → (E) I → a I → b I → Ia 10 I → Ib Trong văn phạm G có ký hiệu non-terminal E (expression) I (identifier) Chú ý luật cú pháp diễn tả định nghĩa đệ quy Trong trường hợp xử lý định nghĩa Định nghĩa thứ lả E(expression), sử dụng ký hiệu non-terminal đinh nghĩa cách quy nạp sử dụng định nghĩa đệ quy a BNF: Trong ngữ cảnh ngôn ngữ lập trình, văn phạm phi ngữ cảnh sủ dụng lần việc định nghĩa ngôn ngữ Algol60 Trong báo cáo giới thiệu Algol60, văn phạm định nghĩa ngôn ngữ mô tả ký hiệu khác với ví dụ mà xét trên, giảm tập ký tự, bỏ ký hiệu mũi tên ( -> ), dấu ngoặc ( { , } ), chữ viết hoa văn phạm phi ngữ cảnh có tên “Backus Naur normal form” (BNF), tên thành viên tổ chức Algol (John Backus người đạo dự án Fortran, viết trình biên dịch cho Fortran, Peter Naur) Trong BNF: Một dẫn xuất chuỗi ab*( a + b ) 𝑬 ⟹𝟑 𝑬 ∗ 𝑬 ⟹𝟏 𝑰 ∗ 𝑬 ⟹𝟏𝟎 𝑰𝒃 ∗ 𝑬 ⟹𝟕 𝒂𝒃 ∗ 𝑬 Trang ⟹𝟔 𝒂𝒃 ∗ (𝑬) ⟹𝟐 𝒂𝒃 ∗ (𝑬 + 𝑬) ⟹𝟏 𝒂𝒃 ∗ (𝑰 + 𝑬) ⟹𝟕 𝒂𝒃 ∗ (𝑰 + 𝑬) ⟹𝟏 𝒂𝒃 ∗ (𝒂 + 𝑰) ⟹𝟖 𝒂𝒃 ∗ (𝒂 + 𝒃) Mũi tên “→” thay “::=” Ký hiệu non-terminal viết giưa dấu ngoặc đơn góc ( ví dụ < 𝐸𝑥𝑝 >) Những luật có vế trái giống nhóm thành khối đơn giản sử dụng ký hiệu “|” để cách biệt luật Ví dụ < 𝐸 >::=< 𝐼 > | < 𝐸 > +< 𝐸 > | < 𝐸 >∗< 𝐸 > | < 𝐸 > −< 𝐸 > |−< 𝐸 > |(< 𝐸 >) b Dẫn xuất ngôn ngữ: Một văn phạm định nghĩa tập chuỗi Chúng ta thấy chuỗi ab*(a+b) hợp lệ với văn phạm ví dụ Chúng ta bắt đầu với ký hiệu khởi tạo E, từ E ta sử dụng luật (3) ta có 𝐸 ⟹3 𝐸 ∗ 𝐸 Bây ta xét vế phải luật, ta có 𝐸 ∗ 𝐸, mà 𝐸 ∗ 𝐸 ⟹1 𝐼 ∗ 𝐸 Chúng ta tiếp tục khai triển I E đến đạt chuỗi dẫn xuất ab*(a+b) Định nghĩa 2.2: Giả sử có văn phạm 𝑮 = 𝑵𝑻, 𝑻, 𝑹, 𝑺 , gán chuỗi 𝑣 𝑣à 𝜔 𝑙ầ𝑦 𝑡ừ 𝑡ậ𝑝 𝑁𝑇 ∪ 𝑇, nói 𝜔 dẫn xuất trực tiếp từ 𝑣, 𝜔 đạt từ 𝑣, trường hợp viết 𝑣 ⇒ 𝜔 Chúng ta nói 𝜔 dẫn xuất từ 𝑣, viết 𝑣 ⇒∗ 𝜔, có tồn chuỗi hữu hạn(có thể chuỗi rỗng) dẫn xuất trực tiếp 𝑣 ⟹ 𝜔0 ⟹ 𝜔1 ⟹ 𝜔2 ⟹ ⋯ ⟹ 𝜔 Sử dụng ký hiệu quy tắc trên, viết sau 𝑬 ∗ 𝑬 ⇒∗ 𝒂𝒃 ∗ (𝒂 + 𝑰) Định nghĩa 2.3 (Generated Language) Ngôn ngữ sản sinh văn phạm 𝑮 = 𝑵𝑻, 𝑻, 𝑹, 𝑺 tập 𝓛 𝑮 = 𝝎 ∈ 𝑻∗ 𝑺 ⇒∗ 𝝎} Trang c Cây dẫn xuất: Dẫn xuất chuỗi trình xử lý tuần tự, có bước phải thực thi theo thứ tự xác Ví dụ văn phạm ⇒10 phải thực thi sau ⇒3 luật (10) viết lại ký hiệu I ( ký hiệu non-terminal), không tồn chuổi khởi tạo Hai dẫn xuất chuỗi ab*(a+b) xây dựng lại cấu trúc chuỗi theo cách giống Hình 1: Cây dẫn xuất chuỗi ab*(a+b) Định nghĩa 2.4 Cho văn phạm 𝑮 = 𝑵𝑻, 𝑻, 𝑹, 𝑺 , dẫn xuất (cây phân tích cú pháp) có thứ tự, đó: Mỗi nút gắn nhãn ký hiệu thuộc tập 𝑁𝑇 ∪ 𝑇 ∪ {𝜖} Gốc dán nhãn S Mỗi nút gán nhãn ký hiệu thuộc tập NT Nếu nút có nhãn 𝐴 ∈ 𝑁𝑇 𝑚1 , 𝑚2,…, 𝑚𝑘 gán nhãn 𝑋1 , 𝑋2,…, 𝑋𝑘 với 𝑋𝑖 ∈ 𝑁𝑇 ∪ 𝑇, (𝑖 ∈ 1, 𝑘 , 𝐴 → 𝑋1 … 𝑋𝐾 ) luật R Trang σ, Var X giá trị v, viết σ [X ← v] để biểu diễn trạng thái mới, trạng giống σ khác từ cách kết hợp X với giá trị v(và mối liên trước X) Với trạng thái σ, biến X, viết σ (X) cho giá trị σ liên hệ với X, giá trị không xác định X không xuất miền σ (σ hàm phần) Ví dụ: Giả sử σ = [(X, 3), (Y, 5), có σ [X ← 7] = [(X, 7), (Y, 5)] Chúng ta có σ (Y) = σ [X← 7] (X) = 7; σ (W) không xác định Quá trình chuyển đổi (Transition) Ngữ nghĩa hoạt động có cấu trúc xem cách hiệu để xác định chức máy tính trừu tượng mà không vào chi tiết việc cài đặt Chức thể bước tính toán máy trừu tượng Cách thức mà ngữ nghĩa hoạt động có cấu trúc xác định ý nghĩa chương trình, c, trình chuyển đổi thể bước chuyển đổi (của trạng thái and/ or chương trình) gây việc thực lệnh Hình thức đơn giản trình chuyển đổi là: < 𝑐, 𝜎 >→ 𝜏 Trong c lệnh, σ trạng thái bắt đầu 𝜏 trạng thái terminal Những ký hiệu nghĩa bắt đầu thực lệnh c trạng thái σ, trình thực thi chấm dứt (trong bước nhất) với trạng thái 𝜏.Ví dụ, trình chuyển đổi định nghĩa lệnh skip là: < 𝒔𝒌𝒊𝒑, 𝜎 >→ 𝜏 Chúng ta có lệnh không làm Bắt đầu từ trạng thái bất kỳ, σ, lệnh skip không làm cả, trạng thái σ không thay đổi.Trong trường hợp phức tạp, trạng thái cuối đạt bước lớn nhất, mà nhiều bước nhỏ mà biến đổi trạng thái (bắt đầu với σ); lệnh, c, thực toàn "tiêu thụ" Các bước thể trình chuyển đổi hình thức: < 𝑐, 𝜎 >→< 𝑐′, 𝜎′ > Ví dụ, trình chuyển đổi định nghĩa lệnh có điều kiện được: < 𝒊𝒇 𝒕𝒕 𝒕𝒉𝒆𝒏 𝑐1 𝒆𝒍𝒔𝒆 𝑐2 , 𝜎 >→< 𝑐1 , 𝜎 > Điều có nghĩa điều kiện boolean đúng, lệnh nhánh sau phải thực Quá trình chuyển đổi có điều kiện mang hình thức quy tắc, thể sau: Trang 18 < 𝑐1 , 𝜎1 >→< 𝑐1′ , 𝜎1′ > < 𝑐2 , 𝜎2 >→< 𝑐2′ , 𝜎2′ > < 𝑐, 𝜎 >→< 𝑐′, 𝜎′ > Chúng ta đọc quy tắc theo cách sau Nếu lệnh, 𝑐1 , trạng thái 𝜎1 , thực bước tính toán biến đổi thành lệnh 𝑐1′ trạng thái 𝜎1′ , lệnh 𝑐2 , trạng thái 𝜎2 , thực bước tính toán chuyển đổi thành lệnh 𝑐2′ , trạng thái 𝜎2′ , sau lệnh c, trang thái σ thực bước tính toán biến đổi thành lệnh 𝑐′ trạng thái 𝜎′ Nó rõ ràng quy tắc cụ thể thể số mối quan hệ có ý nghĩa c, c1 c2 (và trạng thái tương ứng chúng) Nói chung, c1 c2 lệnh c Ngữ nghĩa biểu thức (Expression semantics) Ví dụ cho thấy quy tắc ngữ nghĩa biểu thức số học Ba quy tắc quy tắc termial (có nghĩa là, việc tính toán bên phải mũi tên hình thức mà trình chuyển đổi áp dụng) Chúng xác định ngữ nghĩa biến, bổ sung trường hợp hai summands số, trừ trường hợp hai đối số số kết số tự nhiên Lưu ý ngữ nghĩa cho biểu thức - Nhóm thứ hai bốn quy tắc quy tắc có điều kiện Cặp xác định ngữ nghĩa sum diễn đạt để tính giá trị sum, đánh giá hai đối số Lưu ý ngữ nghĩa không đặc tả thứ tự đánh giá đối số cộng vào, phép trừ xử lý tương tự Hình cho thấy ngữ nghĩa biểu thức hợp lý thông qua ý tưởng tương tự biểu thức số học Lưu ý số này, bv biểu thị giá trị boolean (tt ff) Trang 19 Hình 5: Ngữ nghĩa biểu thức Bool Ngữ nghĩa lệnh (Command semantics) Có thể thấy trạng thái σ luôn không thay đổi trình đánh giá biểu thức sử dụng để đạt giá trị biến Điều thay đổi ngữ nghĩa lệnh hình 2.14 Lưu ý, quy tắc hình hai loại: lệnh, thể bước tính toán thực tế cho lệnh (điều giữ cho quy tắc (c1), (c2), (c4), (c6), (C7) (c9)), phục vụ việc tính toán biểu thức Mô tả ngữ nghĩa ngôn ngữ hoàn tất Trang 20 Tính toán (Computations) Tính toán chuỗi trình chuyển đổi mà mở rộng trình chuyển đổi khác Hơn nữa, chuyển đổi tính toán phải mô tả số quy tắc Ví dụ, xem xét đoạn chương trình c sau: X := 1; while ¬(X == 0) X := (X −1) Giả sử có trạng thái bao gồm tất biến đề cập chương trình, ví dụ, σ = [(X, 6)] Chúng ta tính toán tính toán c σ sau Để viết tắt ký hiệu, viết c để biểu thị lệnh lặp lặp lại ¬ (X ==0) làm X: = (X - 1) Không khó để thấy việc tính toán tạo c sau đây: V Ngữ Dụng Và Cài Đặt Ngữ dụng (Pragmatics) Nếu cho mô tả xác cú pháp ngữ nghĩa ngôn ngữ lập trình, không với tính thực dụng ngôn ngữ Tính thực dụng ngôn ngữ câu trả lời câu hỏi "Mục đích việc xây dựng" Rõ ràng, đó, tính thực dụng ngôn ngữ lập trình thiết lập lần cho tất định nghĩa (định nghĩa cú pháp ngữ nghĩa nó) Ngược lại, phát triển với việc sử dụng ngôn ngữ Tất đề xuất phong cách lập trình phần tính thực dụng Ví dụ, có nguyên tắc nhảy (gotos) cần tránh sử dụng Việc lựa Trang 21 chọn cách thích hợp để đưa tham số vào hàm câu hỏi thực dụng Trong ý nghĩa đó, tính thực dụng ngôn ngữ lập trình trùng hợp với công nghệ phần mềm không nghiên cứu nhiều Mặt khác, làm rõ mục đích sử dụng cấu trúc phần thiết yếu nghiên cứu ngôn ngữ lập trình Cài đặt (Implementation) Cài đặt ngôn ngữ có nghĩa viết trình biên dịch cho nó, thực máy tính trừu tượng cho ngôn ngữ đối tượng trình biên dịch, để viết trình thông dịch thực máy trừu tượng ngôn ngữ, phiên dịch văn Ngoài ra, thực tế, kết hợp hai kỹ thuật sử dụng Mặc dù quy định cụ thể thiết lập việc xây dựng trình thông dịch, nên luôn đặt câu hỏi: "Làm thực hiện?", "Những chi phí gì?" Câu trả lời cho câu hỏi giúp hiểu khía cạnh ngôn ngữ tốt (vì cấu trúc định hình thành theo cách đó), ngôn ngữ thực dụng Trang 22 Phần 2: Xây Dựng Trình Phân Tích Cú Pháp I Định nghĩa văn phạm Chúng ta xem xét văn phạm cho biểu thức toán học sau E = E "+" E | E "-" E | E "*" E | E "/" E | Real | "(" E ")" Văn phạm không diễn đạt tốt cấu trúc biểu thức toán học Trong toán học, phép nhân phép chia có độ ưu tiên cao phép cộng phép trừ Ví dụ biểu thức 4.0+5.0*7.0 nên viết 4.0+(5.0*7.0), kết 39 Một biểu thức số biểu thức dấu ngoặc gọi “factor”, biểu thức bao gồm phép nhân phép chia “factor” gọi “term” Theo thứ tự ưu tiên thi biểu thức dấu ngoặc phải tính trước Chúng ta ký hiệu factor F term T Ta có văn phạm biểu thức toán học sau E = E "+" T | E "-" T | T T = T "*" F | T "/" F | F F = Real | "(" E ")" Các luật cho E phát sinh chuỗi dạng T "+" T "-" · · · "+" T với nhiều T phân cách phép cộng trừ.Tương tự vậy, quy tắc cho T tạo F "*" F "/" · · · "*" F với nhiều F cách phép nhân, chia Lưu ý Real lớp số thực Để tránh quy tắc đệ quy trái, chuyển đổi quy tắc E T sang dạng văn phạm sau E = T Eopt Eopt = "+" T Eopt | "-" T Eopt | Λ T = F Topt Trang 23 Topt = "*" F Topt | "/" F Topt | Λ F = Real | "(" E ")" Thành phần đầu vào luồng ký tự Khi phân tích cú pháp, phải chuyển luồng ký tự thành luồng token, token đại diện cho ký tự terminal II Xây dựng trình phân tích cú pháp C # Định nghĩa token phương thức làm việc Token Trong C# khai báo luồng token đối tượng Ienumerator Phương thức ts.Current để lấy token hành, phương thức ts.MoveNext() đọc token luồng Để báo hiệu đầu vào có lỗi, chương trình ném ngoại lệ có kiểu ApplicationExeption Trình phân tích cú pháp phải truy cập đầu vào thông qua đổi tượng ts (token stream) Kiểu Token phải có thuộc tính có kiểu enum tên Kind để đặc tả kiểu Một token đơn giản, tương ứng với ký hiệu terminal "-" mô ta token có loại enum thiết lập giá trị SUB Vì vậy, mô tả cho token với: khai báo enum, Kind, khai báo cấu trúc, Token public enum Kind { EOF, PLUS, MINUS, MULT, DIV, LPAR, RPAR, NUM } public class Token { public readonly Kind kind; public readonly double nval; private Token(Kind k) { kind = k; nval = 0; } private Token(double n) { kind = Kind.NUM; nval = n; } public override string ToString() { if (kind == Kind.NUM) return "NUM(" + nval + ")"; else return kind.ToString(); } public static Token FromKind(Kind k) { return new Token(k); } public static Token FromDouble(double d) { return new Token(d); } } Để sử dụng tên TokenStream, thay cho System.Collection.Generic.IEnumerator sử dụng sau cách sử dụng khai báo sau: using TokenStream = System.Collections.Generic.IEnumerator ; Xây dựng trình phân tích cú pháp (parser) C # Một trình phân tích cú pháp cho ngữ pháp G xây dựng hệ thống nhờ quy tắc ngữ pháp Trình phân tích cú pháp bao gồm tập hợp phương pháp phân tích cú pháp đệ quy, cho ký hiệu nonterminal ngữ pháp Trang 24 Phương pháp phân tích cú pháp tương ứng với ký hiệu nonterminal A gọi A Nó cố gắng để tìm chuỗi dẫn xuất từ A token hành Nếu thành công, sau trả về, sau đọc nhiều token từ luồng token (token stream) Nếu không thành công, sau ném ngoại lệ lớp ApplicationException Trình phân tích cú pháp G = (T,N,R,S) có dạng void A1 (TokenStream ts) { } void A2 (TokenStream ts) { } void Ak (TokenStream ts) { } void Parse(TokenStream ts) { ts.MoveNext(); S(ts); if (ts.Current.kind != Kind.EOF) throw new ApplicationException("Expected end of file"); return; } {A1, Ak} = N tập hợp các ký hiệu nonterminal S ký hiệu bắt đầu Phương pháp Parse, kiểm tra mà đầu vào lại sau phân tích cú pháp.Nếu phân tích cú pháp thành công, gọi lệnh return để thoát khỏi chường trình, không ném ngoại lệ Như định nghĩa lớp Parser sau public class ArithEvalParser { public double Parse(TokenStream ts) { ts.MoveNext(); double result = E(ts); switch (ts.Current.kind) { case Kind.EOF: return result; default: throw new ApplicationException("Parse error: " + ts.Current); } } double E(TokenStream ts) { return Eopt(T(ts), ts); } double Eopt(double inval, TokenStream ts) { switch (ts.Current.kind) { case Kind.PLUS: Trang 25 ts.MoveNext(); return Eopt(inval + T(ts), ts); case Kind.MINUS: ts.MoveNext(); return Eopt(inval - T(ts), ts); default: return inval; } } double T(TokenStream ts) { return Topt(F(ts), ts); } double Topt(double inval, TokenStream ts) { switch (ts.Current.kind) { case Kind.MULT: ts.MoveNext(); return Topt(inval * F(ts), ts); case Kind.DIV: ts.MoveNext(); return Topt(inval / F(ts), ts); default: return inval; } } double F(TokenStream ts) { switch (ts.Current.kind) { case Kind.NUM: double nval = ts.Current.nval; ts.MoveNext(); return nval; case Kind.LPAR: ts.MoveNext(); double ev = E(ts); if (ts.Current.kind != Kind.RPAR) { throw new ApplicationException("Parse error: expected ’)’"); } ts.MoveNext(); return ev; default: throw new ApplicationException("Parse error: expected number or ’(’"); } } } Scanner Trong trình phân tích cú pháp, đầu vào luồng token Phân tích cú pháp tập tin văn thường chia thành hai giai đoạn Trong giai đoạn đầu, dòng ký tự chuyển đổi thành luồng token, thông tin định dạng (chẳng hạn khoảng trống) văn đầu vào loại bỏ, trình gọi phân tích từ vựng Trong giai đoạn thứ hai, luồng token phân tích cú pháp mô tả phần trước Việc phân chia thành hai giai đoạn đưa cách thuận tiện phép số lượng khoảng trống chữ số tên mà không cho phép khoảng trống bên chữ số tên Một khoảng trống, có nghĩa ký tự trắng, ký tự đặc biệt ký tự xuống dòng Scanner định ký tự chữ số, Trang 26 tên, loại bỏ tất khoảng trống dư thừa, trình phân tích cú pháp không tốn thời gian để xử lý khoảng trống Scanner cài đặt interface Iscanner public interface IScanner { TokenStream Scan(TextReader reader); } Scanner không làm việc trực tiếp với tập tin, thay vào có đối tượng reader có kiểu System.IO.TextReader Điều cho phép tái sử dụng scanner (và phân tích cú pháp) cho đầu vào không đến từ tập tin public class Scanner : IScanner { public TokenStream Scan(TextReader reader) { while (reader.Peek() != -1) { if (Char.IsWhiteSpace((char)reader.Peek())) { reader.Read(); } else if (Char.IsDigit((char)reader.Peek())) { yield return Token.FromDouble(ScanReal(reader)); } else { char c = (char)reader.Read(); switch (c) { case '+': yield return Token.FromKind(Kind.PLUS); break; case '-': yield return Token.FromKind(Kind.MINUS); break; case '*': yield return Token.FromKind(Kind.MULT); break; case '/': yield return Token.FromKind(Kind.DIV); break; case '(': yield return Token.FromKind(Kind.LPAR); break; case ')': yield return Token.FromKind(Kind.RPAR); break; default: throw new ApplicationException("Illegal character: ’" + c + "’"); } } } yield return Token.FromKind(Kind.EOF); } } Chúng ta sử dụng phương thức Char.IsWhiteSpace để kiểm tra ký tự nhập vào ký tự trắng hay không Một số phương thức Char sử dụng phân loại ký tự Ví dụ: Trang 27 IsDigit kiểm tra ký tự có phải chữ số thập phân hay không IsLower kiểm tra xem ký tự có phải ký tự viết thường không IsUpper kiểm tra xem ký tự có phải ký tự viết hoa không IsLetter kiểm tra xem ký hiệu có phải ký tự hay không IsLetterOrDigit kiểm tra ký hiệu có phải ký tự hay ký số không Phân biệt tên định danh với từ khóa ngôn ngữ Hầu hết ngôn ngữ lập trình đề có từ khóa dành riêng Ví dụ C# Java có từ khóa “class”, “interface”, “while” … Trình scanner phân biệt tên từ khóa sau, trình scanner phát định danh, so sánh với danh sách từ khóa Nó phân loại từ khóa có danh sách, không phân loại tên enum Kind { , NAME, CLASS, INTERFACE, WHILE } struct Token { } class Scanner : IScanner { static string ScanName(TextReader reader) { } public IEnumerator Scan(TextReader reader) { while ( reader.Peek() != -1 ) { if ( Char.IsWhiteSpace((char) reader.Peek()) ) { reader.Read(); } else if ( Char.IsLetter((char) reader.Peek()) ) { string sval = ScanName(reader); switch ( sval ) { case "class": yield return Token.FromKind(Kind.CLASS); break; case "interface": yield return Token.FromKind(Kind.INTERFACE); break; case "while": yield return Token.FromKind(Kind.WHILE); break; default: yield return Token.FromString(sval); break; } } else } yield return Token.FromKind(Kind.EOF); } } Chữ số chuỗi ký tự đại diện số, chẳng hạn "3,1414".Chữ số dấu chấm động mô tả văn phạm này: Real = Digits "." Digits Digits = Digit | Digit Digits Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" Trang 28 Phương thức ScanReal(reader) gọi trình scanner phát ký số c static double ScanReal(TextReader reader) { double n = reader.Read() - '0'; while (Char.IsDigit((char)reader.Peek())) n = 10 * n + reader.Read() - '0'; if (reader.Peek() == '.') { reader.Read(); return ScanFrac(n, 0.1, reader); } else return n; } static double ScanFrac(double n, double wt, TextReader reader) { while (Char.IsDigit((char)reader.Peek())) { n += wt * (reader.Read() - '0'); wt /= 10.0; } return n; } Phương thức ScanReal tích lũy giá trị n chữ số trước dấu chẩm phát dấu chấm, ký hiệu ký số không đáp ứng, kết thúc chuỗi đầu vào.Trong trường hợp đầu tiên, phải chữ số sau dấu chấm, sau phương thức ScanFrac gọi Phương pháp ScanFrac tích lũy giá trị chữ số sau dấu chấm ký hiệu ký số xuất Sau đó, trả số quét.Các phương thức scanner cho số thực gọi cách bổ sung thêm phần vào phương pháp Scan Hơn nữa, token phải mở rộng với thuộc tính nval đễ lưu kiểu số double, tương tự cần giá trị enum thêm kiểu enum Kind public TokenStream Scan(TextReader reader) { while (reader.Peek() != -1) { if (Char.IsWhiteSpace((char)reader.Peek())) { reader.Read(); } else if (Char.IsDigit((char)reader.Peek())) { yield return Token.FromDouble(ScanReal(reader)); } else { } } yield return Token.FromKind(Kind.EOF); } Trang 29 Hàm main chƣơng trình minh họa static void Main(string[] args) { IScanner scanner = new Scanner(); ArithEvalParser parser = new ArithEvalParser(); string s = string.Empty;//"(6+3)*2+2*1"; Console.Write("Van pham cho bieu thuc toan hoc:\n"); string grammar grammar grammar grammar grammar = "E = T Eopt " + System.Environment.NewLine; += "Eopt = \"+\" T Eopt | \"-\" T Eopt | ^ \n" += "T = F Topt \n"; += "Topt = \"*\" F Topt | \"/\" F Topt | ^ \n"; += "F = Real | \"(\" E \")\" \n"; Console.Write(grammar + System.Environment.NewLine); while (true) { Console.Write("Nhap bieu thuc toan hoc:"); s = Console.ReadLine(); TextReader r = new StringReader(s); TokenStream tokens = scanner.Scan(r); Console.WriteLine(String.Format("{0}={1}",s, parser.Parse(tokens))); } } Hình 6: Mô tả văn phạm (grammar) biểu thức toán học Hàm Main khởi tạo scanner, scanner phân tích từ vựng trả kết token Trình phân tích cú pháp xử lý token tính kết biểu thức toán học Trang 30 Nhập biểu thức toán học đơn giản theo quy tắc văn phạm, trình phân tích phân tích tính giá trị biểu thức Hình 7: Phân tích tính giá trị biểu thức Trang 31 Tài liệu tham khảo Slide Bài giảng Nguyên Lý Ngôn Ngữ Lập Trình – TS Nguyễn Tuấn Đăng Programming Languages: Principles and Paradigms - Maurizio Gabbrielli and Simone Martini Trang 32 [...]... System.Collections.Generic.IEnumerator ; 2 Xây dựng trình phân tích cú pháp (parser) trong C # Một trình phân tích cú pháp cho một ngữ pháp G có thể được xây dựng một các hệ thống nhờ các quy tắc ngữ pháp Trình phân tích cú pháp sẽ bao gồm một tập hợp các phương pháp phân tích cú pháp đệ quy, cho mỗi ký hiệu nonterminal trong ngữ pháp Trang 24 Phương pháp phân tích cú pháp tương ứng với một ký hiệu nonterminal... trong ngôn ngữ Chúng ta đã biết rằng cây dẫn xuất này mô tả cấu trúc logic của chương trình sẽ được sử dụng bởi các giai đoạn kế tiếp của quá trình biên dịch Cũng có thể xảy ra trường hợp bộ phân tích cú pháp không thể xây dựng được cây dẫn xuất Điều này xảy ra khi các chuỗi đầu vào là không đúng với văn phạm của ngôn ngữ Trong trường hợp này, bộ phân tích cú pháp báo cáo các lỗi đã gặp và quá trình biên... kế của một ngôn ngữ lập trình, hoặc để mô tả một số các đặc điểm riêng của nó, là tối quan trọng để tránh sự mơ hồ với chi phí thấp Phương pháp chính thức cho ngữ nghĩa phân chia thành hai loại chính: ngữ nghĩa biểu hiện và hoạt động Ngữ nghĩa biểu hiện là sự ghép những ngôn ngữ lập trình của các kỹ thuật được phát triển cho ngữ nghĩa của ngôn ngữ toán học Logico Ý nghĩa của một chương trình được đưa... Trong trình phân tích cú pháp, đầu vào là một luồng token Phân tích cú pháp của các tập tin văn bản thường được chia thành hai giai đoạn Trong giai đoạn đầu, dòng ký tự được chuyển đổi thành luồng token, và thông tin định dạng (chẳng hạn như khoảng trống) trong văn bản đầu vào đã được loại bỏ, quá trình này gọi là phân tích từ vựng Trong giai đoạn thứ hai, luồng token được phân tích cú pháp như mô tả. .. chúng ta viết c để biểu thị các lệnh lặp đi lặp lại trong khi ¬ (X ==0) làm X: = (X - 1) Không khó để thấy rằng việc tính toán tạo ra bởi c sau đây: V Ngữ Dụng Và Cài Đặt 1 Ngữ dụng (Pragmatics) Nếu cho một mô tả chính xác cú pháp và ngữ nghĩa của ngôn ngữ lập trình, không đúng với tính thực dụng của ngôn ngữ Tính thực dụng của một ngôn ngữ câu trả lời câu hỏi "Mục đích của việc này là những gì xây dựng" ... luật của R Cây dẫn xuất có thể xây dựng từ các dẫn xuất Nó bắt đầu từ gốc và thêm vào một mức con liên quan đến luật sử dụng trong dân xuất Cây dẫn xuất là một trong những kỹ thuật quan trọng nhất trong việc phân tích cú pháp ngôn ngữ lập trình Cây: Khái niệm cây là một khái niệm quan trọng của ngành khoa học máy tính, được sử dụng nhiều trong các ngôn ngữ chung ( như là cây phả hệ ) Một cây là một... 2 Phân tích cú pháp Khi đã xây dựng xong danh sách các token, bộ phân tích cú pháp tìm cách xây dựng một cây dẫn xuất cho danh sách này Đây là một cây dẫn xuất trong văn phạm của ngôn ngữ Mỗi nút lá của cây này phải tương ứng với một token trong danh sách token đã xây dựng Hơn nữa, các nút lá này, đọc từ trái sang phải sẽ hình thành một cụm từ chính xác (hoặc một chuỗi các ký hiệu terminal) trong ngôn. .. parser.Parse(tokens))); } } Hình 6: Mô tả văn phạm (grammar) của biểu thức toán học Hàm Main khởi tạo scanner, scanner sẽ phân tích từ vựng và trả kết quả về là các token Trình phân tích cú pháp sẽ xử lý các token này và tính kết quả của biểu thức toán học Trang 30 Nhập biểu thức toán học đơn giản theo quy tắc của văn phạm, trình phân tích sẽ phân tích và tính ra giá trị của biểu thức Hình 7: Phân tích và tính giá trị... một ngôn ngữ lập trình trùng hợp với công nghệ phần mềm và không được nghiên cứu nhiều Mặt khác, làm rõ mục đích và sử dụng các cấu trúc là một phần thiết yếu của nghiên cứu của một ngôn ngữ lập trình 2 Cài đặt (Implementation) Cài đặt một ngôn ngữ có nghĩa là viết một trình biên dịch cho nó, cũng như thực hiện một máy tính trừu tượng cho ngôn ngữ đối tượng của trình biên dịch, hoặc để viết một trình. .. quá trình biên dịch sẽ bỏ qua Trong thực tế, phân tích từ vựng và cú pháp được thực hiện xen kẽ (đặc biệt là hai giai đoạn không tuần tự nhưng bộ phân tích tạo ra một token cho từng lời gọi của bộ phân tích cú pháp Văn phạm phổ biến (Regular Grammars) Sự khác nhau giữa phân tích từ vựng và phân tích cú pháp có thể được xác định chính xác bằng cách sử dụng một phân loại chính thức của văn phạm Nếu văn

Ngày đăng: 30/12/2015, 18:36

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan