12/08/2018, 15:36

[Ruby] Tokenization and Parsing

Toeknizations Đã bao nhiêu lần bạn nghĩ rằng Ruby read và trans-forms code của bạn bao nhiêu lần trước khi chạy? Câu trả lời là 3. Bất cứ khi nào bạn chạy code Ruby, Ruby sẽ tách chúng thành các phẩn nhỏ và sau đó đặt chúng lại trong trong các định dạng khác 3 lần. Giữa các lần bạn nhập cdeo ruby ...

  1. Toeknizations Đã bao nhiêu lần bạn nghĩ rằng Ruby read và trans-forms code của bạn bao nhiêu lần trước khi chạy? Câu trả lời là 3. Bất cứ khi nào bạn chạy code Ruby, Ruby sẽ tách chúng thành các phẩn nhỏ và sau đó đặt chúng lại trong trong các định dạng khác 3 lần. Giữa các lần bạn nhập cdeo ruby và những lần bạn thấy kết quả trên console, code Ruby của bạn sẽ trải qua nhiều quá trình liên quan đến công nghệ, kỹ thuật và các công cụ mã nguồn mở. Đầu tiên, Ruby sẽ tokenizes code của bạn, nó sẽ đọc các ký tự trong file và chuyển nó thành các tokens. Sau đó, Ruby sẽ phân tích các token, nhóm các token có nghĩa lại với nhau. Cuối cùng, Ruby biên dịch các câu lệnh này thành các hướng dẫn cấp thấp mà nó có thể thực hiện sau bằng cách sử dụng một máy ảo. Chẳng hạn với đoạn code sau:
10.times do |n|
  puts n
end

Đầu tiên, Ruby sẽ đọc toàn bộ đoạn code trên và chia chúng thành các ký tự: Khi Ruby đã đọc được các ký tự, Ruby sẽ đánh dấu các ký tự này và duyệt tuần tự các ký tự để chuyển thành các tokens hoặc những từ mà Ruby có thể hiểu được. Mã nguồn Ruby C chưa 1 vòng lặp đọc các ký tự và xử lý dự trên các ký tự đó. Đầu tiên, nó sẽ đọc ký tự '1' - 1 con số, Ruby sẽ lặp lại việc này cho đến khi tìm thấy 1 ký tự không phải là số. Ở bước này, Ruby đọc được ký tự '.'. Ruby sẽ quan tâm liệu đây có phải là 1 con số hay không bởi vì nó có thể là 1 floating-point.

Bây giờ, Ruby sẽ dừng việc iterating vì 't' không phải là 1 numberic. Ruby sẽ xem giai đoạn này là 1 phần của 1 token riêng biệt và nó trở lại 1 bước: Tiếp theo, Ruby sẽ chuyển những con số vừa tìm được vào vào token đầu tiên của chương trình, gọi là tINTEGER. Ruby tiếp tục tiếp tục đọc qua các ký tự, và chuyển thành các token, nhóm các ký tự cần thiết lại với nhau. Tiếp theo, Ruby sẽ tìm được từ "times" và tạo ra 1 identifier token. (Idenfiers là các từ thường refer đến biến, method hoặc tên lớp). Tiếp theo, Ruby sẽ tìm được từ do, 1 keyword trong Ruby. Cuối cùng, Ruby sẽ chuyển các ký tự còn lại thành các tokens. Ripper Tools: Hãy thử đoạn code sau:

 require "ripper"
   require 'pp'
   code = <<STR
   10.times do |n|
puts n end
STR
puts code
pp Ripper.lex(code)

Chạy đoạn code trên, ta sẽ được như sau: Như hình ở trên, các tokens nhận được là 10 - int, times - identifier, do - keyword, n - identifier, end - keyword. 2. Parsing Sau khi Ruby đã chuyển code của bạn thành các token, nó sẽ làm gì tiếp theo? Liệu lúc này nó đã hiểu và chạy được chương trình của bạn? Hẳn là không đơn giản như vậy. Bước tiếp theo, Ruby sẽ parsing các tokens và nhóm chúng lại thành các câu, cụm từ có nghĩa. Khi parsing, Ruby tính đến thứ tự hoạt động, phương pháp, khối và các cấu trúc mã lớn hơn khác. Giống như nhiều ngôn ngữ khác, Ruby sử dụng một parser generator là Bison (phiển bản mới hơn của Yacc). Trước khi bạn chạy chương trình, Ruby sử dụng Bison để tạo mã trình phân tích cú pháp (parse.c) từ quy tắc ngữ pháp le (parse.y). Sau đó, lúc thực thi, mã trình tạo phân tích cú pháp này phân tích các mã thông báo trả lại bởi mã tokenizer của Ruby.

0