Điều đầu tiên bạn cần hiểu là không ai bắt bạn phải viết trình phân tích cú pháp hoặc trình biên dịch theo một cách nhất định. Cụ thể, không nhất thiết là kết quả của trình phân tích cú pháp phải là một cây. Nó có thể là bất kỳ cấu trúc dữ liệu phù hợp để đại diện cho đầu vào.
Ví dụ: ngôn ngữ sau:
prog:
definition
| definition ';' prog
;
definition: .....
có thể được trình bày dưới dạng một danh sách các định nghĩa. (Nitopperers sẽ chỉ ra rằng một danh sách là một cây thoái hóa, nhưng dù sao đi nữa.)
Thứ hai, không cần phải giữ cây phân tích cú pháp (hoặc bất kỳ cấu trúc dữ liệu nào mà trình phân tích cú pháp trả về). Ngược lại, trình biên dịch thường được xây dựng như một chuỗi các đường chuyền, biến đổi kết quả của đường chuyền trước đó. Do đó bố cục tổng thể của trình biên dịch có thể là như vậy:
parser :: String -> Maybe [Definitions] -- parser
pass1 :: [Definitions] -> Maybe DesugaredProg -- desugarer
pass2 :: DesugaredProg -> Maybe TypedProg -- type checker
pass3 :: TypedProg -> Maybe AbstractTargetLang -- code generation
pass4 :: AbstractTargetLang -> Maybe String -- pretty printer
compiler :: String -> Maybe String -- transform source code to target code
compiler source = do
defs <- parser source
desug <- pass1 defs
typed <- pass2 desug
targt <- pass3 typed
pass4 targt
Bottom Line: Nếu bạn nghe người ta nói về cây phân tích cú pháp , cây syntac trừu tượng , cây cú pháp bê tông vv, luôn luôn thay thế bởi cấu trúc dữ liệu phù hợp với mục đích trao , và bạn đang sử dụng tốt.