Sự khác biệt giữa cây cú pháp trừu tượng và cây cú pháp cụ thể là gì?


84

Tôi đã đọc một chút về cách hoạt động của trình thông dịch / trình biên dịch và một lĩnh vực mà tôi đang bối rối là sự khác biệt giữa AST và CST. Sự hiểu biết của tôi là trình phân tích cú pháp tạo ra một CST, giao nó cho bộ phân tích ngữ nghĩa để biến nó thành AST. Tuy nhiên, sự hiểu biết của tôi là trình phân tích ngữ nghĩa đơn giản đảm bảo rằng các quy tắc được tuân thủ. Tôi thực sự không hiểu tại sao nó thực sự thực hiện bất kỳ thay đổi nào để làm cho nó trở nên trừu tượng hơn là cụ thể.

Có điều gì đó mà tôi thiếu về trình phân tích ngữ nghĩa, hay sự khác biệt giữa AST và CST có phần giả tạo?

Câu trả lời:


62

Một cây cú pháp cụ thể thể hiện chính xác văn bản nguồn ở dạng được phân tích cú pháp. Nói chung, nó tuân theo ngữ pháp không có ngữ cảnh xác định ngôn ngữ nguồn.

Tuy nhiên, ngữ pháp cụ thể và cây có rất nhiều thứ cần thiết để làm cho văn bản nguồn có thể phân tích cú pháp rõ ràng, nhưng không đóng góp vào ý nghĩa thực tế. Ví dụ: để triển khai ưu tiên toán tử, CFG của bạn thường có một số cấp độ của các thành phần biểu thức (số hạng, nhân tố, v.v.), với các toán tử kết nối chúng ở các cấp độ khác nhau (bạn thêm các thuật ngữ để nhận biểu thức, các thuật ngữ được bao gồm các yếu tố được nhân tùy chọn , Vân vân.). Tuy nhiên, để thực sự diễn giải hoặc biên dịch ngôn ngữ, bạn không cần điều này; bạn chỉ cần các nút Biểu thức có các toán tử và toán hạng. Cây cú pháp trừu tượng là kết quả của việc đơn giản hóa cây cú pháp cụ thể xuống những thứ thực sự cần thiết để thể hiện ý nghĩa của chương trình. Cây này có định nghĩa đơn giản hơn nhiều và do đó dễ xử lý hơn trong các giai đoạn thực thi sau này.

Bạn thường không cần thực sự xây dựng một cây cú pháp cụ thể. Các thói quen hành động trong ngữ pháp YACC (hoặc Antlr, hoặc Menhir, hoặc bất cứ thứ gì ...) của bạn có thể trực tiếp xây dựng cây cú pháp trừu tượng, vì vậy cây cú pháp cụ thể chỉ tồn tại như một thực thể khái niệm đại diện cho cấu trúc phân tích cú pháp của văn bản nguồn của bạn.


2
Bổ sung: trình thông dịch Python đầu tiên xây dựng CST và sau đó chuyển đổi thành AST.
cgsdfc

33

Một cây cú pháp cụ thể phù hợp với những gì các quy tắc ngữ pháp nói là cú pháp. Mục đích của cây cú pháp trừu tượng là có một biểu diễn "đơn giản" về những gì cần thiết trong "cây cú pháp".

Giá trị thực trong AST IMHO là nó nhỏ hơn CST, và do đó mất ít thời gian hơn để xử lý. (Bạn có thể nói, ai quan tâm chứ? Nhưng tôi làm việc với một công cụ mà chúng ta có hàng chục triệu nút sống cùng một lúc!).

Hầu hết các trình tạo phân tích cú pháp có bất kỳ hỗ trợ nào cho việc xây dựng cây cú pháp đều nhấn mạnh rằng bạn chỉ định chính xác cách chúng được xây dựng theo giả định rằng các nút cây của bạn sẽ "đơn giản" hơn CST (và trong đó, chúng thường đúng, vì các lập trình viên khá lười biếng). Có thể cho rằng điều đó có nghĩa là bạn phải viết mã các hàm ít người truy cập cây hơn, và điều đó cũng có giá trị, ở chỗ nó giảm thiểu năng lượng kỹ thuật. Khi bạn có 3500 quy tắc (ví dụ: đối với COBOL), điều này quan trọng. Và sự "đơn giản" này dẫn đến tính chất tốt của "sự nhỏ bé".

Nhưng có những AST như vậy tạo ra một vấn đề không có ở đó: nó không khớp với ngữ pháp, và bây giờ bạn phải theo dõi cả hai. Và khi có 1500 nút AST cho ngữ pháp quy tắc 3500, điều này rất quan trọng. Và nếu ngữ pháp phát triển (chúng luôn luôn như vậy!), Bây giờ bạn có hai tập hợp khổng lồ để đồng bộ hóa.

Một giải pháp khác là để trình phân tích cú pháp đơn giản tạo các nút CST cho bạn và chỉ sử dụng các nút đó. Đây là một lợi thế lớn khi xây dựng ngữ pháp: không cần phải phát minh ra 1500 nút AST đặc biệt để mô hình hóa 3500 quy tắc ngữ pháp. Chỉ cần nghĩ về cái cây là đồng nghĩa với ngữ pháp. Theo quan điểm của kỹ sư ngữ pháp, điều này là hoàn toàn không có trí tuệ, điều này cho phép anh ta tập trung vào việc hiểu đúng ngữ pháp và đánh giá nó vào nội dung của trái tim anh ta. Có thể cho rằng bạn phải viết nhiều quy tắc truy cập nút hơn, nhưng điều đó có thể được quản lý. Thêm về điều này sau.

Những gì chúng tôi làm với Bộ công cụ cải tiến phần mềm DMS là tự động xây dựng một CST dựa trên kết quả của quá trình phân tích cú pháp (GLR). Sau đó, DMS tự động tạo CST "nén" vì lý do hiệu quả về dung lượng, bằng cách loại bỏ các đầu cuối mang giá trị (từ khóa, dấu chấm câu), các sản phẩm đơn nguyên vô dụng về mặt ngữ nghĩa và tạo danh sách cho các cặp quy tắc ngữ pháp được liệt kê như:

    L = e ;
    L = L e ;
    L2 = e2 ;
    L2 = L2  ','  e2 ;

và một loạt các biến thể của các hình thức như vậy. Bạn nghĩ về các quy tắc ngữ pháp và CST ảo; công cụ này hoạt động trên biểu diễn nén. Dễ dàng trên bộ não của bạn, nhanh hơn / nhỏ hơn trong thời gian chạy.

Đáng chú ý, CST nén được xây dựng theo cách này trông rất giống AST mà bạn có thể đã thiết kế bằng tay (xem liên kết ở cuối các ví dụ). Đặc biệt, CST nén không mang bất kỳ nút nào chỉ là cú pháp cụ thể. Có một số điểm khó xử: ví dụ: trong khi các nút cụ thể cho '(' và ')' được tìm thấy theo kiểu cổ điển trong các chương trình con biểu thức không có trong cây, thì một "nút trong dấu ngoặc đơn" lại xuất hiện trong CST được nén và phải được xử lý. Một AST thực sự sẽ không có điều này. Đây có vẻ như là một cái giá khá nhỏ phải trả để thuận tiện cho việc không phải chỉ định việc xây dựng AST, bao giờ hết. Và tài liệu cho cây luôn có sẵn và chính xác: ngữ pháp tài liệu.

Làm thế nào để chúng ta tránh "khách thêm"? Chúng tôi không hoàn toàn, nhưng DMS cung cấp một thư viện AST để hướng dẫn AST và xử lý sự khác biệt giữa CST và AST một cách minh bạch. DMS cũng cung cấp bộ đánh giá "ngữ pháp thuộc tính" (AGE), là một phương pháp để chuyển các giá trị được tính toán cho các nút lên và xuống cây; AGE xử lý tất cả các vấn đề về biểu diễn cây và vì vậy kỹ sư công cụ chỉ lo lắng về việc viết các phép tính một cách hiệu quả trực tiếp trên chính các quy tắc ngữ pháp. Cuối cùng, DMS cũng cung cấp các mẫu "cú pháp bề mặt", cho phép các đoạn mã từ ngữ pháp được sử dụng để tìm các loại cây con cụ thể mà không cần biết hầu hết các loại nút liên quan.

Một trong những câu trả lời khác cho rằng nếu bạn muốn xây dựng các công cụ có thể tái tạo nguồn, AST của bạn sẽ phải phù hợp với CST. Điều đó không thực sự đúng, nhưng việc tạo lại nguồn sẽ dễ dàng hơn nhiều nếu bạn có các nút CST. DMS tự động tạo ra hầu hết các ứng dụng xinh đẹp vì nó có quyền truy cập vào cả hai: -}

Điểm mấu chốt: ASTs rất tốt cho các loại thực phẩm nhỏ, cả thực vật và khái niệm. Xây dựng AST tự động từ CST cung cấp cả hai và cho phép bạn tránh vấn đề theo dõi hai tập hợp khác nhau.

CHỈNH SỬA Tháng 3 năm 2015: Liên kết đến các ví dụ về CST so với "AST" được xây dựng theo cách này


25

Điều này dựa trên ngữ pháp Công cụ đánh giá biểu thức của Terrence Parr.

Ngữ pháp cho ví dụ này:

grammar Expr002;

options 
{
    output=AST;
    ASTLabelType=CommonTree; // type of $stat.tree ref etc...
}

prog    :   ( stat )+ ;

stat    :   expr NEWLINE        -> expr
        |   ID '=' expr NEWLINE -> ^('=' ID expr)
        |   NEWLINE             ->
        ;

expr    :   multExpr (( '+'^ | '-'^ ) multExpr)*
        ; 

multExpr
        :   atom ('*'^ atom)*
        ; 

atom    :   INT 
        |   ID
        |   '('! expr ')'!
        ;

ID      : ('a'..'z' | 'A'..'Z' )+ ;
INT     : '0'..'9'+ ;
NEWLINE : '\r'? '\n' ;
WS      : ( ' ' | '\t' )+ { skip(); } ;

Đầu vào

x=1
y=2
3*(x+y)

Cây phân tích cú pháp

Cây phân tích cú pháp là một đại diện cụ thể của đầu vào. Cây phân tích cú pháp giữ lại tất cả thông tin của đầu vào. Các ô trống đại diện cho khoảng trắng, tức là cuối dòng.

Cây phân tích cú pháp

AST

AST là một đại diện trừu tượng của đầu vào. Lưu ý rằng parens không có trong AST vì các liên kết có thể bắt nguồn từ cấu trúc cây.

AST

BIÊN TẬP

Để biết thêm thông qua giải thích, hãy xem Trình biên dịch và Trình tạo trình biên dịch trang pg. 23


20

Bài đăng trên blog này có thể hữu ích.

Đối với tôi, dường như AST "ném đi" rất nhiều thông tin cấu trúc / ngữ pháp trung gian mà không đóng góp vào ngữ nghĩa. Ví dụ, bạn không quan tâm rằng 3 là một nguyên tử là một số hạng là một thừa số là một .... Bạn chỉ quan tâm rằng đó là 3khi bạn đang thực hiện biểu thức lũy thừa hoặc bất cứ điều gì.


9

Cây cú pháp cụ thể tuân theo các quy tắc ngữ pháp của ngôn ngữ. Về ngữ pháp, "danh sách biểu thức" thường được xác định bằng hai quy tắc

  • biểu_sách có thể là: biểu thức
  • biểu_sách có thể là: biểu_thức, biểu_thức

Theo nghĩa đen, hai quy tắc này cung cấp hình dạng chiếc lược cho bất kỳ danh sách biểu thức nào xuất hiện trong chương trình.

Cây cú pháp trừu tượng ở dạng thuận tiện cho việc thao tác thêm. Nó đại diện cho mọi thứ theo cách có ý nghĩa đối với một người hiểu được ý nghĩa của các chương trình, chứ không chỉ là cách chúng được viết. Danh sách biểu thức ở trên, có thể là danh sách các đối số của một hàm, có thể được biểu diễn một cách thuận tiện dưới dạng vectơ của biểu thức, vì phân tích tĩnh tốt hơn nên có tổng số biểu thức có sẵn một cách rõ ràng và có thể truy cập từng biểu thức bằng mục lục.


2

Đơn giản, AST chỉ chứa ngữ nghĩa của mã, Cây phân tích cú pháp / CST cũng bao gồm thông tin về cách chính xác mã được viết.


1

Cây cú pháp cụ thể chứa tất cả thông tin như dấu ngoặc đơn thừa, khoảng trắng và chú thích, cây cú pháp trừu tượng sẽ loại bỏ thông tin này.

 

NB: thật buồn cười, khi bạn triển khai một công cụ tái cấu trúc, AST của bạn sẽ lại chứa tất cả thông tin cụ thể, nhưng bạn sẽ tiếp tục gọi nó là AST vì đó đã trở thành thuật ngữ tiêu chuẩn trong lĩnh vực này (vì vậy người ta có thể nói nó đã từ lâu trước đây đã mất nghĩa gốc).


Chà, nó có thể không có tất cả thông tin cụ thể. Tất cả những gì được yêu cầu là nó có thể tạo lại thông tin đó. Hãy xem câu trả lời của tôi.
Ira Baxter

Đã nhận xét ngày hôm qua? VẬY lỗi hoặc có một huy hiệu người hành nghề bình luận nào mà tôi không biết? :) (Tái bút: nhưng rất vui khi được nghe ý kiến ​​của bạn, bạn vừa tình cờ thấy cuộc nói chuyện về Công nghệ của Google trên DMS…)
akuhn

1

Đó là một sự khác biệt mà không tạo ra sự khác biệt.

AST thường được giải thích là một cách để xác định gần đúng ngữ nghĩa của biểu thức ngôn ngữ lập trình bằng cách loại bỏ nội dung từ vựng. Ví dụ: trong ngữ pháp không có ngữ cảnh, bạn có thể viết quy tắc EBNF sau

term: atom (('*' | '/') term )*

trong khi trong trường hợp AST, bạn chỉ sử dụng mul_rulediv_rule thể hiện các phép toán số học thích hợp.

Không thể giới thiệu những quy tắc đó trong ngữ pháp ngay từ đầu sao? Tất nhiên. Bạn có thể viết lại quy tắc ngắn gọn và trừu tượng ở trên bằng cách phá vỡ nó thành một quy tắc cụ thể hơn được sử dụng để bắt chước các nút AST đã đề cập:

term: mul_rule | div_rule
mul_rule: atom ('*' term)*
div_rule: atom ('/' term)*

Bây giờ, khi bạn nghĩ về phân tích cú pháp từ trên xuống thì thuật ngữ thứ hai giới thiệu xung đột FIRST / FIRST giữa mul_rulediv_rule mà một trình phân tích cú pháp LL (1) không thể giải quyết. Hình thức quy tắc đầu tiên là phiên bản bên trái của quy tắc thứ hai đã loại bỏ cấu trúc một cách hiệu quả. Bạn phải trả một số giải thưởng cho việc sử dụng LL (1) ở đây.

Vì vậy, AST là một bổ sung đặc biệt được sử dụng để sửa chữa những thiếu sót của ngữ pháp và trình phân tích cú pháp. Chuyển đổi CST -> AST là một động thái tái cấu trúc. Không ai từng bận tâm khi có thêm dấu phẩy hoặc dấu hai chấm trong cây cú pháp. Ngược lại, một số tác giả trang bị thêm chúng vào AST vì họ thích sử dụng AST để thực hiện tái cấu trúc thay vì duy trì nhiều cây khác nhau cùng một lúc hoặc viết thêm một công cụ suy luận. Lập trình viên lười biếng vì những lý do chính đáng. Trên thực tế, họ lưu trữ thông tin dòng và cột chẵn được thu thập bằng phân tích từ vựng trong AST để báo cáo lỗi. Quả thực rất trừu tượng.


0

CST (Concrete Syntax Tree) là một dạng cây biểu diễn Ngữ pháp (Quy tắc về cách chương trình được viết). Tùy thuộc vào kiến ​​trúc trình biên dịch, nó có thể được sử dụng bởi Trình phân tích cú pháp để tạo ra AST.

AST (Abstract Syntax Tree) là một đại diện dạng cây của nguồn được phân tích cú pháp, được tạo ra bởi phần phân tích cú pháp của trình biên dịch. Nó lưu trữ thông tin về mã thông báo + ngữ pháp.

Tùy thuộc vào kiến ​​trúc của trình biên dịch của bạn, CST có thể được sử dụng để tạo AST. Công bằng mà nói CST phát triển thành AST. Hoặc, AST là một CST phong phú hơn.

Có thể tìm thấy nhiều giải thích hơn trên liên kết này: http://eli.thegreenplace.net/2009/02/16/abstract-vs-concrete-syntax-trees#id6


1
Tôi nghĩ rằng những điều này cần được làm rõ, đặc biệt là về "đơn giản hóa" Tôi có xu hướng xem nó là "phức tạp" ít nhất là về mặt khái niệm, điều ngược lại, và vẫn mô tả không có gì hữu ích.
Joshua Hedges

1
Tôi đã thay đổi -1 của mình thành +1. Tôi cảm thấy rằng những điều bạn đã làm là đủ.
Joshua Hedges
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.