2009-10-04 5 views
5

Tôi muốn biết các chiến lược tốt để triển khai ngôn ngữ dành riêng cho miền phải chạy dưới ít nhất 2 ngôn ngữ (Java, C#) và có thể nhiều hơn (Python và có thể là Javascript).viết một ngôn ngữ cụ thể cho miền di động

Một số nền. Chúng tôi đã phát triển và triển khai một ngôn ngữ dành riêng cho miền hiện được viết bằng C#. Nó được triển khai mặc dù một loạt các lời gọi phương thức mà các đối số của nó là các ngôn ngữ chung (chuỗi, gấp đôi, vv), Bộ sưu tập (IEnumerable, HashSet, ...) hoặc các đối tượng trong một thư viện miền cụ thể (CMLMolecule, Point3, RealSquareMatrix). Thư viện được kiểm tra tốt và các đối tượng phải tuân thủ một lược đồ XML được triển khai ổn định để thay đổi sẽ được tiến hóa và được quản lý (ít nhất đó là hy vọng).

Chúng tôi hy vọng ngôn ngữ sẽ được sử dụng bởi một cộng đồng máy tính rộng và một phần, được sử dụng để hack các giải pháp của riêng họ mà không cần kiểm soát trung tâm. Lý tưởng nhất là DSL sẽ tạo ra một mức độ đóng gói và sản xuất các chức năng cần thiết mà họ cần. Các thư viện sẽ quản lý các thuật toán chi tiết có nhiều và đa dạng nhưng khá nổi tiếng. Có rất nhiều điểm chung với các yêu cầu của DSL trong Domain-specific languages vs. library of functions.

Tôi đánh giá cao ý tưởng về kiến ​​trúc tốt nhất (rõ ràng khi được triển khai, chúng tôi không thể dễ dàng quay lại). Các lựa chọn bao gồm ít nhất:

  • Tạo IDL (ví dụ: thông qua CORBA). W3C đã làm điều này cho DOM XML - tôi ghét nó - và có vẻ như quá mức cần thiết
  • tạo thủ công các chữ ký tương tự cho mỗi nền tảng và nỗ lực tốt nhất để giữ chúng đồng bộ.
  • Tạo ngôn ngữ có thể phân tích cú pháp (ví dụ: CSS).
  • lập trình khai báo trong XML (c.f. XSLT). Đây là giải pháp ưa thích của tôi vì nó có thể được tìm kiếm, thao tác, v.v.

Hiệu suất không quan trọng. Rõ ràng mục đích là.

EDIT Đã có cuộc thảo luận về việc liệu các cuộc gọi ứng dụng có phải là một DSL hay không. Tôi đã phát hiện ra sự giới thiệu của Martin Fowler về DSL (http://martinfowler.com/dslwip/Intro.html), nơi ông lập luận rằng các cuộc gọi phương thức đơn giản (hoặc các cuộc gọi có chuỗi) có thể được gọi là DSL. Vì vậy, một loạt như:

point0 = line0.intersectWith(plane); 
point1 = line1.intersectWith(plane); 
midpoint = point0.midpoint(point1); 

có thể được coi là một DSL

+1

Một lớn tiêu cực đến bất kỳ ngôn ngữ thể hiện trong XML. Bạn sẽ có ý định một nhà phát triển làm việc trực tiếp với XML hoặc đó sẽ là định dạng lưu trữ/thời gian chạy? Người phát minh ra ANT nói XML là lựa chọn sai và anh ta sẽ chọn khác nếu anh ta có thể thay đổi mọi thứ. – SteveD

+0

@stevendick. Cảm ơn, tôi nghe những gì bạn nói. Cá nhân tôi là một người nghiện XML nhưng tôi cố gắng giữ một tâm trí cởi mở. –

+0

Hãy xem những gì tác giả gốc của ANT phải nói: http://web.archive.org/web/20040602210721/x180.net/Articles/Java/AntAndXML.html Đừng mù quáng theo XML- Mô hình Golden Hammer. Nếu bạn định tạo một DSL đọc và được viết bởi những người thực tế, hãy xem xét sử dụng một trong nhiều công cụ lexer/parser tốt đẹp thay vì XML. Có rất nhiều công cụ tốt đẹp những ngày này (như ANTLR) mà thực hiện điều này thực tế. Viết lexers/parsers không phải là đau đớn bây giờ như nó đã từng là khi lex/yacc là nhà nước-of-the-nghệ thuật. –

Trả lời

6

Dường như có sự mơ hồ trong câu hỏi giữa ngôn ngữ và thư viện. Các thuật ngữ "DSL nội bộ" và "DSL bên ngoài" hữu ích và tôi nghĩ là do Martin Fowler.

DSL "bên ngoài" có thể là công cụ dòng lệnh độc lập. Nó được truyền qua một chuỗi nguồn, nó phân tích nó bằng cách nào đó, và làm điều gì đó với nó. Không có giới hạn thực sự về cách cú pháp và ngữ nghĩa có thể hoạt động. Nó cũng có thể được cung cấp như một thư viện bao gồm chủ yếu là một phương thức giống như eval; một ví dụ phổ biến sẽ xây dựng một truy vấn SQL dưới dạng một chuỗi và gọi phương thức execute trong thư viện RDBMS; không phải là một mô hình sử dụng rất dễ chịu hoặc thuận tiện, và kinh khủng nếu lan truyền xung quanh một chương trình trên quy mô lớn.

DSL "nội bộ" là thư viện được viết theo cách để tận dụng lợi thế của các ngôn ngữ của máy chủ (mục đích chung) để tạo ấn tượng rằng một ngôn ngữ mới có thể được nhúng bên trong ngôn ngữ hiện có. Trong các ngôn ngữ có nhiều cú pháp (C++, C#), điều này có nghĩa là sử dụng toán tử quá tải theo những cách nghiêm trọng kéo dài (hoặc bỏ qua) ý nghĩa thông thường của ký hiệu toán tử. Có nhiều ví dụ trong C++; một vài trong C# cũng - các Irony parser toolkit mô phỏng BNF một cách khá hạn chế mà hoạt động tốt.

Cuối cùng, có một thư viện cũ đơn giản: các lớp, phương pháp, thuộc tính, với các tên được lựa chọn tốt.

DSL bên ngoài sẽ cho phép bạn bỏ qua hoàn toàn các vấn đề tích hợp ngôn ngữ chéo, vì phần giống thư viện duy nhất sẽ là phương thức eval. Nhưng phát minh ra chuỗi công cụ của riêng bạn là không tầm thường. Mọi người luôn quên tầm quan trọng to lớn của việc gỡ lỗi, intellisense, làm nổi bật cú pháp, vv

DSL nội bộ có lẽ là một nỗ lực vô nghĩa nếu bạn muốn làm tốt trên C# và Java. Vấn đề là nếu bạn tận dụng lợi thế của các quirks của một ngôn ngữ máy chủ, bạn sẽ không nhất thiết phải có thể lặp lại các trick trên ngôn ngữ khác. ví dụ. Java không có quá tải toán tử.

Thư nào rời khỏi thư viện cũ đơn giản. Nếu bạn muốn trải dài C# và Java (ít nhất), thì bạn có phần bị mắc kẹt về mặt lựa chọn ngôn ngữ triển khai. Bạn có thực sự muốn viết thư viện hai lần không? Một khả năng là viết thư viện trong Java, và sau đó sử dụng IKVM để biên dịch chéo nó thành các hội đồng .NET. Điều này sẽ đảm bảo cho bạn một giao diện giống nhau trên cả hai nền tảng đó.

Mặt khác, API sẽ được biểu thị bằng các tính năng mẫu số chung thấp nhất - có nghĩa là, các tính năng Java :). Không có thuộc tính, chỉ có các phương thức getX/setX. Chỉ đạo rõ ràng của generics vì hai hệ thống khá khác nhau trong sự tôn trọng đó. Ngoài ra, ngay cả cách tiêu chuẩn của phương pháp đặt tên khác nhau giữa hai (camelCase so với PascalCase), do đó, một nhóm người dùng sẽ ngửi thấy một con chuột.

+0

@Earwicker +1 tổng quan hữu ích. Sự tham gia của Java và C# là một (không may). Tôi chắc chắn sẽ thử IKVM. Tôi không nhớ mất tài sản và các generics rất đơn giản. Quy ước đặt tên có thể được tự động hóa, tôi hy vọng. Tôi nhận thức được vấn đề phát minh ra chuỗi công cụ của riêng mình và đây là một bản tóm tắt hữu ích. –

+0

Có, không nghi ngờ gì bạn có thể viết một công cụ có thể sửa chữa quy ước đặt tên. Thậm chí bạn có thể làm điều gì đó tương tự cho các thuộc tính - hãy tìm cặp phương thức getX/setX (mặc dù có lẽ một dấu thuộc tính sẽ là cần thiết vì không phải tất cả các phương thức getX đều phù hợp với cú pháp thuộc tính, ví dụ: đôi khi chúng có hiệu ứng phụ nhìn thấy được). –

+1

@Earwicker. Đây là ý tưởng hiện tại của tôi. Giảm các cuộc gọi đến một tập hợp con chung của nhiều ngôn ngữ nhất có thể (ví dụ: không sử dụng các thuộc tính, chắc chắn không phải là quá tải toán tử). –

1

Khả năng chạy trốn lên ngôn ngữ thực hiện trong trường hợp bạn cần phải làm điều gì đó mà chỉ không được hỗ trợ bởi DSL của bạn, hoặc vì lý do hiệu suất (mặc dù tôi nhận ra đó không phải là một ưu tiên).

Tôi đang nghiên cứu DSL để thực hiện quy tắc trong một công cụ quy tắc trong C#, một số quy tắc thực sự phức tạp và có thể thay đổi đáng kể trong tương lai, vì vậy có thể thoát ra ngoài C# thực sự hữu ích. Tất nhiên điều này phá vỡ khả năng tương thích nền tảng, nhưng nó thực sự chỉ là một cách để hack xung quanh các trường hợp cạnh mà không cần phải thay đổi DSL của bạn.

+1

@Dale. Vâng!Sẽ có trường hợp cạnh và không có lý do tại sao họ không nên bị buộc tội theo cách này và sau đó có thể tóm tắt và tổng quát sau này. Tôi hy vọng rằng các chức năng thư viện chính sẽ được tiếp xúc, vì vậy chúng tôi sẽ không có một cổng duy nhất. –

0

Bạn sẽ giảm giá tốt nhất bằng văn bản cho thư viện trong C (hoặc một số ngôn ngữ như rpython mà sẽ tạo ra C-code) và sau đó sử dụng SWIG hoặc tương tự để tạo ra các ràng buộc ngôn ngữ cụ thể cho C#, Java, vv Python

Lưu ý rằng cách tiếp cận này sẽ không giúp ích nếu bạn đang sử dụng Javascript trong trình duyệt - bạn sẽ phải viết thư viện javascript riêng biệt. Nếu bạn đang sử dụng javascript thông qua Rhino, thì bạn có thể sử dụng các ràng buộc Java.

0

Có thể diễn giải JavaScript từ bên trong chương trình Java trực tiếp bằng cách sử dụng công cụ tập lệnh và dường như cũng từ C#. Python có thể chạy trên JVM và công cụ .NET.

Tôi khuyên bạn nên điều tra các tùy chọn này, sau đó viết thư viện của bạn trong một tập hợp con chung của các đường dẫn thực hiện có sẵn cho ngôn ngữ bạn chọn. Tôi sẽ không xem xét việc viết nó bằng ngôn ngữ yêu cầu dịch và chuyển đổi bài viết, vì bạn giới thiệu một bước có thể rất, rất khó để gỡ lỗi trong trường hợp có vấn đề.

2

Mặc dù tôi không muốn quảng bá dự án của mình quá nhiều, tôi muốn đề cập đến PIL, a Platform Independent Language, một ngôn ngữ trung gian mà tôi đang làm việc để hỗ trợ nhiều nền tảng phần mềm (như Java, Python, ...) , đặc biệt cho các DSL bên ngoài.Ý tưởng chung là bạn tạo mã trong PIL (một tập hợp con của Java), trình biên dịch PIL sau đó có thể dịch sang một trong nhiều ngôn ngữ khác, hiện tại chỉ là Java hoặc Python, nhưng nhiều hơn sẽ được thêm vào trong tương lai.

Tôi đã trình bày một bài báo về hội thảo về Kỹ thuật phần mềm và ngôn ngữ khoảng 2 ngày trước, bạn có thể tìm thấy một liên kết tới việc xuất bản trang web PIL (pil-lang.org), nếu bạn quan tâm.

+0

Tôi đã cố gắng loại điều này một vài năm trước đây và nó rất hữu ích để xem những người làm nó khá tốt hơn. –

3

Nếu bạn sẵn sàng mô tả lại ngôn ngữ của mình bằng cách sử dụng ANTLR, bạn có thể tạo trình thông dịch DSL bằng nhiều ngôn ngữ mà không phải tự bảo trì chúng bao gồm tất cả ngôn ngữ bạn đã đề cập cùng với nhiều ngôn ngữ khác.

Antlr là trình tạo trình phân tích cú pháp/lexer và có nhiều ngôn ngữ đích. Điều này cho phép bạn mô tả ngôn ngữ của bạn một lần, mà không cần phải duy trì nhiều bản sao của ngôn ngữ đó.

Xem toàn bộ danh sách ngôn ngữ đích here.

+0

Tôi thích cá nhân ý tưởng này. Tất nhiên đó là một bước nhảy vọt lớn và khó rút lui từ –

+0

Đúng, có một đường cong học tập với Antlr và StringTemplate. Nhưng cá nhân, tôi thích nó. Tôi đang tìm kiếm nhiều hơn và nhiều vấn đề hơn có thể được giải quyết với một ngữ pháp được mô tả đơn giản. Cuối cùng thời gian bạn mất trong quá trình chuyển đổi, bạn sẽ nhiều hơn bù đắp cho tiết kiệm bảo trì. –

0

Tôi muốn mở rộng câu trả lời của Darien. Tôi nghĩ rằng ANTLR mang lại một cái gì đó cho bảng mà vài công cụ lexer/parser khác cung cấp (ít nhất là kiến ​​thức của tôi). Nếu bạn muốn tạo một DSL mà cuối cùng tạo ra Java và mã C#, ANTLR thực sự tỏa sáng.

ANTLR cung cấp bốn thành phần cơ bản:

  • lexer Grammar (phá vỡ đầu vào suối vào tokens)
  • Parser Grammar (tổ chức thẻ vào một cây cú pháp trừu tượng)
  • Tree Grammar (đi bộ cú pháp trừu tượng và đưa siêu dữ liệu vào một công cụ tạo mẫu)
  • StringTemplate (một công cụ mẫu dựa trên các nguyên tắc lập trình chức năng)

Ngôn ngữ lexer, parser và cây của bạn có thể vẫn độc lập với ngôn ngữ được tạo cuối cùng của bạn. Thực tế, công cụ StringTemplate hỗ trợ các nhóm logic các định nghĩa mẫu. Nó thậm chí còn cung cấp cho kế thừa giao diện của các nhóm mẫu. Điều này có nghĩa là bạn có thể có các bên thứ ba sử dụng trình phân tích cú pháp ANTLR của bạn để tạo ra python, assembly, c, hoặc ruby, khi tất cả các bạn ban đầu được cung cấp là đầu ra java và C#. Ngôn ngữ đầu ra của DSL của bạn có thể dễ dàng được mở rộng khi yêu cầu thay đổi theo thời gian.

Để nhận được nhiều nhất của ANTLR bạn sẽ muốn đọc phần sau đây:

The Definitive ANTLR Reference: Building Domain-Specific Languages

Language Implementation Patterns: Create Your Own Domain-Specific and General Programming Languages