2009-07-23 28 views
8

G'day!Làm thế nào tôi có thể xây dựng một ngữ pháp sạch, giống Python trong ANTLR?

Làm cách nào để xây dựng một ngữ pháp ANTLR đơn giản xử lý các biểu thức nhiều dòng mà không cần dấu chấm phẩy hoặc dấu gạch chéo ngược?

Tôi đang cố gắng để viết một DSL đơn giản cho các biểu thức:

# sh style comments 
ThisValue = 1 
ThatValue = ThisValue * 2 
ThisOtherValue = (1 + 2 + ThisValue * ThatValue) 
YetAnotherValue = MAX(ThisOtherValue, ThatValue) 

Nói chung, tôi muốn ứng dụng của tôi để cung cấp các kịch bản với một số giá trị được đặt tên ban đầu và kéo ra kết quả cuối cùng. Tuy nhiên, tôi đang bị treo trên cú pháp. Tôi muốn hỗ trợ nhiều biểu thức dòng như sau:

# Note: no backslashes required to continue expression, as we're in brackets 
# Note: no semicolon required at end of expression, either 
ThisValueWithAReallyLongName = (ThisOtherValueWithASimilarlyLongName 
           +AnotherValueWithAGratuitouslyLongName) 

Tôi bắt đầu với một ngữ pháp ANTLR như thế này:

exprlist 
    : (assignment_statement | empty_line)* EOF! 
    ; 
assignment_statement 
    : assignment NL!? 
    ; 
empty_line 
    : NL; 
assignment 
    : ID '=' expr 
    ; 

// ... and so on 

Có vẻ như đơn giản, nhưng tôi đã gặp rắc rối với dòng mới:

warning(200): StackOverflowQuestion.g:11:20: Decision can match input such as "NL" using multiple alternatives: 1, 2 
As a result, alternative(s) 2 were disabled for that input 

mặt đồ họa, trong org.antlr.works.IDE:

Decision Can Match NL Using Multiple Alternatives http://img.skitch.com/20090723-ghpss46833si9f9ebk48x28b82.png

tôi đã đá ngữ pháp xung quanh, nhưng luôn luôn kết thúc với hành vi vi phạm hành vi mong đợi:

  • Một newline không cần vào cuối của tập tin
  • dòng rỗng được chấp nhận
  • Mọi thứ trong một dòng từ dấu thăng đơn trở lên sẽ bị loại bỏ dưới dạng nhận xét
  • Bài tập kết thúc bằng cuối dòng, không dấu chấm phẩy
  • Biểu thức có thể trải dài nhiều dòng nếu được bọc trong ets

Tôi có thể tìm thấy ví dụ về ngữ pháp ANTLR với nhiều đặc điểm này. Tôi thấy rằng khi tôi cắt chúng xuống để hạn chế sự biểu cảm của họ chỉ là những gì tôi cần, tôi sẽ phá vỡ một thứ gì đó. Những người khác thì quá đơn giản, và tôi phá vỡ chúng khi tôi thêm tính biểu cảm.

Tôi nên dùng góc nào với ngữ pháp này? Bạn có thể chỉ ra bất kỳ ví dụ nào không phải là ngôn ngữ hoàn chỉnh tầm thường hoặc đầy đủ không?

Trả lời

6

tôi sẽ cho phép tokenizer bạn làm các việc nâng nặng hơn là trộn quy tắc xuống dòng của bạn vào ngữ pháp của bạn:

  • Đếm dấu ngoặc đơn, dấu ngoặc, và niềng răng, và không tạo ra thẻ NL trong khi có nhóm không khép kín . Điều đó sẽ cung cấp cho bạn dòng tiếp tục miễn phí mà không có ngữ pháp của bạn là bất kỳ khôn ngoan hơn.

  • Luôn tạo mã thông báo NL ở cuối tệp có hay không dòng cuối cùng kết thúc bằng ký tự '\n', sau đó bạn không phải lo lắng về trường hợp đặc biệt của câu lệnh không có NL. Báo cáo luôn luôn kết thúc bằng NL.

Điểm thứ hai sẽ cho phép bạn đơn giản hóa ngữ pháp của bạn để một cái gì đó như thế này:

exprlist 
    : (assignment_statement | empty_line)* EOF! 
    ; 
assignment_statement 
    : assignment NL 
    ; 
empty_line 
    : NL 
    ; 
assignment 
    : ID '=' expr 
    ; 
+0

Bây giờ tôi cần phải tìm ra cách để có được tokenizer để làm điều đó nâng nặng. Quay lại tài liệu, tôi đoán vậy. :) –

+0

John, nó vẫn eludes tôi. Cú pháp ngữ pháp ANTLR có trình nạp mã thông báo NL trước EOF là gì? –

+0

+1 Đối với luôn kết thúc trên một dòng mới, làm cho mọi thứ sạch hơn rất nhiều. Cảm ơn. – Craz

0

Làm thế nào về điều này?

exprlist 
    : (expr)? (NL+ expr)* NL!? EOF! 
    ; 
expr 
    : assignment | ... 
    ; 
assignment 
    : ID '=' expr 
    ; 
0

Tôi giả sử bạn đã chọn đặt NL tùy chọn, vì câu lệnh cuối cùng trong mã đầu vào của bạn không phải kết thúc bằng dòng mới.

Trong khi nó có ý nghĩa rất nhiều, bạn đang làm cho cuộc sống của bạn khó khăn hơn rất nhiều cho trình phân tích cú pháp của bạn. Các dấu hiệu tách biệt (như NL) nên được ấp ủ, vì chúng phân biệt và làm giảm cơ hội xung đột.

Trong trường hợp của bạn, trình phân tích cú pháp không biết liệu nó có nên phân tích cú pháp "chuyển nhượng NL" hay "chuyển nhượng empty_line" hay không. Có rất nhiều cách để giải quyết nó, nhưng hầu hết trong số họ chỉ là các trợ lý cho một lựa chọn thiết kế không khôn ngoan.

Đề xuất của tôi là một bản hack vô tội: Hãy bắt buộc NL và luôn thêm NL vào cuối luồng đầu vào của bạn!

Dường như nó có vẻ hơi không rõ ràng, nhưng thực tế nó sẽ giúp bạn tiết kiệm rất nhiều đau đầu trong tương lai.

Các vấn đề liên quan