Tôi có thể thực thi những loại mẫu nào trên mã để giúp dịch sang ngôn ngữ lập trình khác dễ dàng hơn? [đóng cửa]


95

Tôi đang chuẩn bị thực hiện một dự án phụ có mục tiêu là dịch mã từ ngôn ngữ lập trình này sang ngôn ngữ lập trình khác. Các ngôn ngữ tôi đang bắt đầu là PHP và Python (Python sang PHP sẽ dễ bắt đầu hơn), nhưng lý tưởng nhất là tôi có thể thêm các ngôn ngữ khác một cách dễ dàng (tương đối). Kế hoạch là:

  • Điều này hướng tới phát triển web. Mã gốc và mã đích sẽ nằm trên các khuôn khổ (mà tôi cũng sẽ phải viết). Các khuôn khổ này sẽ bao gồm một mẫu thiết kế MVC và tuân theo các quy ước mã hóa nghiêm ngặt. Điều này sẽ làm cho việc dịch dễ dàng hơn.

  • Tôi cũng đang xem xét IOC và phương pháp tiêm phụ thuộc, vì chúng có thể giúp quá trình dịch dễ dàng hơn và ít mắc lỗi hơn.

  • Tôi sẽ sử dụng mô-đun phân tích cú pháp của Python, mô-đun này cho phép tôi làm quen với Cây cú pháp trừu tượng. Rõ ràng thứ gần nhất mà tôi có thể nhận được với PHP là token_get_all () , đây là một bước khởi đầu.

  • Từ đó tôi có thể xây dựng AST, bảng ký hiệu và điều khiển luồng.

Sau đó, tôi tin rằng tôi có thể bắt đầu xuất mã. Tôi không cần một bản dịch hoàn hảo . Tôi sẽ vẫn phải xem lại mã đã tạo và khắc phục sự cố. Tốt nhất là người dịch nên gắn cờ các bản dịch có vấn đề.

Trước khi bạn hỏi "Mục đích của việc này là gì?" Câu trả lời là ... Đó sẽ là một trải nghiệm học tập thú vị. Nếu bạn có bất kỳ thông tin chi tiết nào về cách làm cho việc này bớt khó khăn hơn, vui lòng cho tôi biết.


BIÊN TẬP:

Tôi quan tâm hơn đến việc biết những loại mẫu nào tôi có thể thực thi trên mã để giúp dịch mã dễ dàng hơn (ví dụ: IoC, SOA?) Mã hơn là cách thực hiện dịch.


6
Bạn đã xem xét các hệ thống như .NET CLR hoặc Perl6's Parrot chưa? Chúng biên dịch một tập hợp các ngôn ngữ thành một biểu diễn trung gian có thể được chạy bởi một trình thông dịch chung. Nếu bạn có thể sao lưu từ biểu diễn trung gian sang một ngôn ngữ, bạn đã có một trình dịch.
Borealid

1
@Borealid AFAIK .NET CIL là (tương đối) dễ dàng để biên dịch vào , nhưng may mắn nhận được có thể đọc được mã trở lại từ đó. Nhìn Parrot bây giờ.
NullUserException

Có các dự án tương tự cho các ngôn ngữ khác; Tôi không chắc tác giả của chúng giàu đến mức nào. Và tôi thực sự đang kiềm chế bản thân rất nhiều ở đây, bằng cách cần một khuôn khổ và tuân thủ các quy ước mã hóa nghiêm ngặt.
NullUserException

2
Tôi không thể bổ sung bất kỳ kiến ​​thức cụ thể nào, nhưng bạn đã xem pyjamas ( pyjs.org ), cụ thể là translate.py chưa? Đây là một trình biên dịch python sang javascript.
stephan,

3
CHỈNH SỬA: Nếu bạn có quyền kiểm soát mã sẽ được dịch, điều rõ ràng nhất cần làm là tránh các cấu trúc khó dịch! Ví dụ, C dễ dàng hơn để dịch sang Java nếu không có bất kỳ số học con trỏ nào. Đối với Python, có lẽ tôi sẽ tránh xa các lệnh đóng. Điều khác bạn có thể làm là viết mã nguồn theo cách mà các phần khó dịch hơn luôn được mã hóa theo kiểu thành ngữ, giúp chúng dễ dàng nhận ra và xử lý các trường hợp đặc biệt.
Ira Baxter

Câu trả lời:


122

Tôi đã xây dựng các công cụ (Bộ công cụ cải tiến phần mềm DMS) để thực hiện thao tác chương trình với mục đích chung (với dịch ngôn ngữ là một trường hợp đặc biệt) từ năm 1995, được hỗ trợ bởi một nhóm các nhà khoa học máy tính mạnh mẽ. DMS cung cấp phân tích cú pháp chung, xây dựng AST, bảng ký hiệu, điều khiển và phân tích luồng dữ liệu, áp dụng các quy tắc dịch, tái tạo văn bản nguồn với chú thích, v.v., tất cả đều được tham số hóa bằng các định nghĩa rõ ràng về ngôn ngữ máy tính.

Số lượng máy móc bạn cần để làm tốt điều này là rất lớn (đặc biệt nếu bạn muốn có thể làm điều này cho nhiều ngôn ngữ theo cách chung), và sau đó bạn cần trình phân tích cú pháp đáng tin cậy cho các ngôn ngữ có định nghĩa không đáng tin cậy (PHP là ví dụ hoàn hảo về điều này ).

Không có gì sai khi bạn nghĩ về việc xây dựng một trình dịch ngôn ngữ sang ngôn ngữ khác hoặc thử nó, nhưng tôi nghĩ rằng bạn sẽ thấy đây là một nhiệm vụ lớn hơn nhiều đối với các ngôn ngữ thực tế hơn bạn mong đợi. Chúng tôi đã đầu tư khoảng 100 năm công chỉ vào DMS và thêm 6-12 tháng nữa cho mỗi định nghĩa ngôn ngữ "đáng tin cậy" (bao gồm định nghĩa mà chúng tôi đã dày công xây dựng cho PHP), nhiều hơn thế nữa đối với các ngôn ngữ khó chịu như C ++. Nó sẽ là một "địa ngục của một kinh nghiệm học tập"; nó đã dành cho chúng tôi. (Bạn có thể thấy phần Tài liệu kỹ thuật tại trang web trên rất thú vị để bắt đầu việc học đó).

Mọi người thường cố gắng tạo ra một số loại máy móc tổng quát bằng cách bắt đầu với một số công nghệ mà họ quen thuộc, thực hiện một phần công việc. (Các AST trong Python là một ví dụ tuyệt vời). Tin tốt là một phần của công việc đã hoàn thành. Tin xấu là máy móc có hàng triệu giả định được tích hợp sẵn, hầu hết trong số đó bạn sẽ không phát hiện ra cho đến khi bạn cố gắng giành giật nó để làm một việc khác. Tại thời điểm đó, bạn phát hiện ra rằng máy móc có dây để làm những gì ban đầu của nó, và thực sự, sẽ thực sự chống lại nỗ lực của bạn để bắt nó làm một việc khác. (Tôi nghi ngờ việc cố gắng lấy Python AST để lập mô hình PHP sẽ rất thú vị).

Lý do tôi bắt đầu xây dựng DMS ban đầu là để xây dựng các nền tảng có rất ít giả định như vậy được xây dựng sẵn. Nó có một số điều khiến chúng tôi đau đầu. Cho đến nay, không có lỗ đen. (Phần khó nhất trong công việc của tôi trong 15 năm qua là cố gắng ngăn những giả định như vậy len lỏi vào).

Nhiều người cũng mắc sai lầm khi cho rằng nếu họ có thể phân tích cú pháp (và có thể lấy được AST), họ đang trên đường làm một điều gì đó phức tạp. Một trong những bài học khó là bạn cần các bảng ký hiệu và phân tích luồng để phân tích hoặc chuyển đổi chương trình tốt. ASTs là cần thiết nhưng không đủ. Đây là lý do mà cuốn sách biên dịch của Aho & Ullman không dừng lại ở chương 2. (OP có quyền này ở chỗ ông ấy đang có kế hoạch chế tạo thêm máy móc ngoài AST). Để biết thêm về chủ đề này, hãy xem Cuộc sống sau khi phân tích cú pháp .

Nhận xét về "Tôi không cần một bản dịch hoàn hảo" thật rắc rối. Những gì những người dịch yếu làm là chuyển đổi 80% mã "dễ", để lại 20% khó làm bằng tay. Nếu ứng dụng bạn định chuyển đổi khá nhỏ và bạn chỉ định chuyển đổi nó một lần tốt, thì 20% đó là OK. Nếu bạn muốn chuyển đổi nhiều ứng dụng (hoặc thậm chí cùng một ứng dụng với những thay đổi nhỏ theo thời gian), điều này không tốt chút nào. Nếu bạn cố gắng chuyển đổi 100K SLOC thì 20% là 20.000 dòng mã gốc khó dịch, khó hiểu và sửa đổi trong ngữ cảnh của 80.000 dòng chương trình đã dịch khác mà bạn chưa hiểu. Điều đó cần một lượng lớn nỗ lực. Ở cấp độ dòng triệu, điều này đơn giản là không thể trong thực tế.khó hơn và họ thường phát hiện ra một cách đau đớn với sự chậm trễ trong thời gian dài, chi phí cao và thường thất bại hoàn toàn.)

Những gì bạn phải làm để dịch các hệ thống quy mô lớn là tỷ lệ chuyển đổi chín mươi phần trăm cao, hoặc có khả năng là bạn không thể hoàn thành phần thủ công của hoạt động dịch.

Một lưu ý quan trọng khác là kích thước của mã được dịch. Cần rất nhiều năng lượng để xây dựng một phiên dịch viên hoạt động hiệu quả, mạnh mẽ, ngay cả với những công cụ tốt. Mặc dù có vẻ hấp dẫn và thú vị khi xây dựng một trình dịch thay vì chỉ thực hiện chuyển đổi thủ công, nhưng đối với các cơ sở mã nhỏ (ví dụ: lên đến khoảng 100K SLOC theo kinh nghiệm của chúng tôi), kinh tế học đơn giản là không biện minh cho điều đó. Không ai thích câu trả lời này, nhưng nếu bạn thực sự phải dịch chỉ 10K SLOC mã, có lẽ tốt hơn hết bạn nên cắn viên đạn và thực hiện nó. Và vâng, điều đó thật đau đớn.

Tôi coi các công cụ của chúng tôi là cực kỳ tốt (nhưng sau đó, tôi khá thiên vị). Và vẫn rất khó để xây dựng một dịch giả giỏi; chúng tôi mất khoảng 1,5-2 năm công và chúng tôi biết cách sử dụng các công cụ của mình. Sự khác biệt là với quá nhiều máy móc này, chúng ta thành công thường xuyên hơn nhiều so với thất bại.


8
Bạn đã bao giờ cân nhắc việc đóng góp định nghĩa PHP "được xây dựng một cách đau đớn" của mình trở lại cộng đồng PHP nói chung, hoặc kết hợp quá chặt chẽ với nguồn doanh thu của riêng bạn để làm cho điều đó khả thi chưa?
TML

53
Rất nhiều người đã yêu cầu tôi làm mọi thứ chúng tôi làm thành "mã nguồn mở", những người không muốn đóng góp vào nguồn doanh thu và không có năng lượng để tự mình thực hiện công việc và tạo nguồn mở. Nếu bạn chỉ đóng góp một phần nhỏ cho một dự án rất lớn, và / hoặc bạn có một nguồn thu nhập khác, thì "nguồn mở" có vẻ ổn. Nếu bạn đã tự mình làm tất cả công việc và nguồn thu nhập duy nhất của bạn, thì điều này sẽ kém hấp dẫn hơn rất nhiều. [Tôi không muốn thảo luận về giá trị tương đối của triết lý "phần mềm miễn phí", vì vậy tôi sẽ không tham gia vào bất kỳ bình luận nào sau này dọc theo dòng này]
Ira Baxter

9
Tôi đồng ý với những gì bạn nói ở đây, đó là lý do tại sao tôi diễn đạt câu hỏi như tôi đã làm. Tôi đoán rằng chúng tôi sẽ hiểu từ phản hồi đó rằng bạn cảm thấy nó quá chặt chẽ với doanh thu của bạn và hoàn toàn không có gì sai với điều đó - tôi chỉ nghĩ điều đó đáng để hỏi.
TML

3
@IraBaxter Bạn chỉ cần nói những thành ngữ phổ biến về pratices liên quan đến máy tính có thể áp dụng cho rất nhiều pratices khác. Điều duy nhất xen kẽ trong tất cả những gì bạn đã viết là các liên kết đến semanticdesigns.com (tình cờ là công ty của bạn)
cờ amirouche

1
Bạn thường cung cấp liên kết đến các trang liên quan đến Clang trong câu trả lời của mình. Điều đó chỉ chứng minh rằng ai đó khác có thể tạo ra một trang web. Hầu hết chúng ta đều cho rằng một trang web được viết tốt ngụ ý rằng có một công việc thực sự nghiêm túc đằng sau chứ không chỉ là một số nỗ lực gian lận để đánh lừa người đọc như bạn dường như ngụ ý trong câu trả lời của mình. Bạn có thực sự tin rằng trang web đó là lừa đảo? Trang chứa thông tin tham khảo đến nguồn "có liên quan"; nó được ẩn danh vì hợp đồng cho công việc yêu cầu điều đó. Điều đó tôi không thể giúp được.
Ira Baxter

13

Câu trả lời của tôi sẽ giải quyết nhiệm vụ cụ thể của việc phân tích cú pháp Python để dịch nó sang một ngôn ngữ khác, chứ không phải các khía cạnh cấp cao hơn mà Ira đã giải quyết tốt trong câu trả lời của mình.

Tóm lại: không sử dụng mô-đun phân tích cú pháp, có một cách dễ dàng hơn.

Các astmô-đun, có sẵn từ Python 2.6 là phù hợp hơn cho nhu cầu của bạn, vì nó cung cấp cho bạn một AST làm sẵn để làm việc với. Tôi đã viết một bài báo về vấn đề này vào năm ngoái, nhưng nói tóm lại, hãy sử dụng parsephương pháp astphân tích cú pháp mã nguồn Python thành AST. Các parsermô-đun sẽ cho em cả rừng cây phân tích cú pháp, không phải là một AST. Hãy cảnh giác với sự khác biệt .

Bây giờ, vì AST của Python khá chi tiết, với AST, công việc front-end không quá khó. Tôi cho rằng bạn có thể có một nguyên mẫu đơn giản cho một số phần của chức năng đã sẵn sàng khá nhanh. Tuy nhiên, để có được một giải pháp hoàn chỉnh sẽ mất nhiều thời gian hơn, chủ yếu là do ngữ nghĩa của các ngôn ngữ là khác nhau. Một tập hợp con đơn giản của ngôn ngữ (các hàm, các kiểu cơ bản, v.v.) có thể được dịch dễ dàng, nhưng khi bạn đi vào các lớp phức tạp hơn, bạn sẽ cần máy móc hạng nặng để mô phỏng cốt lõi của ngôn ngữ này sang ngôn ngữ khác. Ví dụ: hãy xem xét các trình tạo và hiểu danh sách của Python không tồn tại trong PHP (theo kiến ​​thức tốt nhất của tôi, được thừa nhận là kém khi tham gia PHP).

Để cung cấp cho bạn một mẹo cuối cùng, hãy xem xét 2to3công cụ được tạo bởi các nhà phát triển Python để dịch mã Python 2 sang mã Python 3. Front-end-khôn ngoan, nó có hầu hết các yếu tố bạn cần để dịch Python sang một thứ gì đó . Tuy nhiên, vì lõi của Python 2 và 3 là tương tự nhau nên không cần máy móc mô phỏng ở đó.


Weeeell. 2to3chỉ là AST đến AST. Nó không hỗ trợ làm bất cứ điều gì vượt quá khả năng của astmô-đun. Lưu ý rằng tất cả các bản dịch đi từ cú pháp được hỗ trợ bởi quá trình python máy chủ đến cú pháp được hỗ trợ bởi quá trình python máy chủ. Không có trình dịch nào thêm, nói, chú thích chức năng, bởi vì 2.6 không hỗ trợ nó.
habnabit

... và câu hỏi của OP có thể được đóng khung, ngắn hạn, làm thế nào để chuyển từ Python 2.6 AST thành ... một cái gì đó trong PHP. Mô-đun ast có thể sẽ không muốn đại diện tốt cho cú pháp PHP, vì vậy nó thậm chí không phải là ast thành ast.
Ira Baxter

2
@Aaron: 2to3có thể được xem như một ví dụ về việc sử dụng AST được tạo ra từ ast.
Eli Bendersky

AFAIK, 2to3 được cho là một bản dịch dễ dàng hơn Python sang PHP (sau tất cả, Python sang Python của nó, phải không)? Và thậm chí nó không hoạt động đặc biệt tốt. Lưu ý rằng số lượng lớn Python 2.6 vẫn chưa được chuyển qua 2to3 ... bởi vì chắc chắn có một loạt các bản vá lỗi bản dịch bài đăng vẫn phải được thực hiện. Nếu được tự động hóa 100%, Python 2.6 sẽ chết.
Ira Baxter

5

Viết một phiên dịch không phải là không thể, đặc biệt là khi Joel's Intern đã làm điều đó trong một mùa hè.

Nếu bạn muốn làm một ngôn ngữ, thật dễ dàng. Nếu bạn muốn làm nhiều hơn, nó sẽ khó hơn một chút, nhưng không quá nhiều. Phần khó nhất là, trong khi bất kỳ ngôn ngữ hoàn chỉnh nào có thể làm những gì mà một ngôn ngữ hoàn chỉnh khác làm, thì các kiểu dữ liệu tích hợp có thể thay đổi những gì một ngôn ngữ thực hiện một cách phi thường.

Ví dụ:

word = 'This is not a word'
print word[::-2]

mất rất nhiều mã C ++ để sao chép (ok, bạn có thể làm điều đó khá ngắn với một số cấu trúc lặp, nhưng vẫn vậy).

Đó là một chút sang một bên, tôi đoán.

Bạn đã bao giờ viết tokenizer / parser dựa trên ngữ pháp ngôn ngữ chưa? Có thể bạn sẽ muốn học cách làm điều đó nếu chưa, vì đó là phần chính của dự án này. Những gì tôi sẽ làm là nghĩ ra một cú pháp hoàn chỉnh Turing cơ bản - một thứ khá giống với mã bytecode của Python . Sau đó, bạn tạo lexer / parser có ngữ pháp ngôn ngữ (có thể sử dụng BNF ) và dựa trên ngữ pháp, biên dịch ngôn ngữ đó thành ngôn ngữ trung gian của bạn. Sau đó, những gì bạn muốn làm là làm ngược lại - tạo một trình phân tích cú pháp từ ngôn ngữ của bạn thành các ngôn ngữ đích dựa trên ngữ pháp.

Vấn đề rõ ràng nhất mà tôi thấy là lúc đầu có thể bạn sẽ tạo mã kém hiệu quả khủng khiếp , đặc biệt là trong các ngôn ngữ * mạnh hơn như Python.

Nhưng nếu bạn làm theo cách này thì có thể bạn sẽ tìm ra cách để tối ưu hóa kết quả đầu ra khi tiếp tục. Tóm lại:

  • đọc ngữ pháp được cung cấp
  • biên dịch chương trình thành cú pháp trung gian (nhưng cũng hoàn thành Turing)
  • biên dịch chương trình trung cấp sang ngôn ngữ cuối cùng (dựa trên ngữ pháp được cung cấp)
  • ...?
  • Lợi nhuận!(?)

* mạnh mẽ, ý tôi là điều này có 4 dòng:

myinput = raw_input("Enter something: ")
print myinput.replace('a', 'A')
print sum(ord(c) for c in myinput)
print myinput[::-1]

Chỉ cho tôi một ngôn ngữ khác có thể làm điều gì đó như vậy trong 4 dòng và tôi sẽ chỉ cho bạn một ngôn ngữ mạnh mẽ như Python.


“Bạn đã bao giờ viết tokenizer / parser dựa trên ngữ pháp ngôn ngữ chưa?” Tôi đã làm việc đó bằng JavaCC.
NullUserException

2
Thực tập sinh của Joel đã làm một phần công việc trong một mùa hè. Ngôn ngữ nguồn của anh ấy là một tập hợp con của một ngôn ngữ hiện có, và có lẽ tập hợp con này có thể được điều chỉnh phần nào. Điều đó làm cho công việc dễ dàng hơn rất nhiều. Tương tự, NullPointerException có thể muốn bắt đầu với các phần dễ dàng hơn của Python, có thể chuyển qua phần khó hơn để chuyển đổi thủ công (như đã lưu ý trong các câu hỏi).
David Thornley

@NullUserException: Bạn sẽ có một số tiếp xúc, nhưng về cơ bản bạn sẽ thực hiện lại JavaCC, chỉ thay vì Java làm ngôn ngữ đầu ra, bạn sẽ thực hiện <insert langauge here>. @David, khá như vậy. Ngay cả Thistle cũng cần một số trợ giúp về một số cấu trúc ngôn ngữ. Nếu tôi là OP, tôi muốn đi cho chức năng đầu tiên, sau đó tối ưu hóa, nếu không tôi sẽ bị mắc kẹt mãi mãi cố gắng để có được C ++ để làm chuỗi cắt (với bước): p
Wayne Werner

@WayneWerner Đối với hồ sơ, các ngôn ngữ như C # hoàn toàn không yêu cầu dòng mới. (Ít nhất, không phải sau khi bạn loại bỏ các nhận xét đơn dòng.) Vì vậy, bạn có thể viết bất kỳ chương trình C # nào trong một dòng. Nhưng tất nhiên tôi hiểu những gì bạn đang nhận được.
leviathanbadger

@ aboveyou00: Tôi không nghĩ điều đó đúng. Nếu bạn không cho phép các điều kiện tiền xử lý, bạn có thể đúng.
Ira Baxter

3

Có một vài câu trả lời cho bạn biết đừng bận tâm. Chà, điều đó hữu ích như thế nào? Bạn muốn học? Bạn có thể học. Đây là biên dịch. Nó chỉ xảy ra rằng ngôn ngữ đích của bạn không phải là mã máy, mà là một ngôn ngữ cấp cao khác. Điều này được thực hiện mọi lúc.

Có một cách tương đối dễ dàng để bắt đầu. Đầu tiên, hãy truy cập http://sourceforge.net/projects/lime-php/ (nếu bạn muốn làm việc bằng PHP) hoặc một số trang như vậy và xem qua mã ví dụ. Tiếp theo, bạn có thể viết một trình phân tích từ vựng bằng cách sử dụng một chuỗi các biểu thức chính quy và mã nguồn cấp dữ liệu cho trình phân tích cú pháp mà bạn tạo. Các hành động ngữ nghĩa của bạn có thể xuất mã trực tiếp bằng ngôn ngữ khác hoặc xây dựng một số cấu trúc dữ liệu (nghĩ đối tượng, người đàn ông) mà bạn có thể xoa bóp và duyệt qua để tạo mã đầu ra.

Bạn may mắn với PHP và Python vì chúng là ngôn ngữ giống nhau, nhưng có cú pháp khác nhau. Phần khó là vượt qua sự khác biệt về ngữ nghĩa giữa các dạng ngữ pháp và cấu trúc dữ liệu. Ví dụ, Python có danh sách và từ điển, trong khi PHP chỉ có mảng assoc.

Phương pháp tiếp cận "người học" là xây dựng thứ gì đó hoạt động tốt cho một tập hợp con hạn chế của ngôn ngữ (chẳng hạn như chỉ các câu lệnh in, phép toán đơn giản và phép gán biến), sau đó loại bỏ dần các giới hạn. Về cơ bản đó là những gì mà các “ông lớn” trong lĩnh vực này đều đã làm.

Ồ, và vì bạn không có kiểu tĩnh trong Python, nên tốt nhất bạn nên viết và dựa vào các hàm PHP như "python_add" để thêm số, chuỗi hoặc đối tượng theo cách Python thực hiện.

Rõ ràng, điều này có thể trở nên lớn hơn nhiều nếu bạn để nó.


3
Thực ra tôi không nói "đừng làm phiền". Những gì tôi đã nói là, "dịch ngôn ngữ theo những cách nói chung là rất khó". Nếu OP tiếp tục con đường ban đầu của anh ấy là sử dụng cây Python để thử và tạo PHP, anh ấy sẽ học được rất nhiều và tôi đều ủng hộ kinh nghiệm học tập; Tôi cũng bắt đầu ở đó. Anh ấy sẽ không thể thêm ngôn ngữ mới một cách dễ dàng.
Ira Baxter

@IraBaxter Tôi không thể hỗ trợ câu lệnh của bạn, thực hiện Python-> PHP và PHP-> Javascript sẽ khá dễ dàng. cf. phần cuối của stackoverflow.com/a/22850139/140837 ở giữa câu trả lời, tôi cũng giải quyết "tranh luận" của bạn
amirouche

2

Tôi sẽ thứ hai về quan điểm của @EliBendersky liên quan đến việc sử dụng ast.parse thay vì phân tích cú pháp (mà trước đây tôi không biết). Tôi cũng nhiệt liệt khuyên bạn nên xem lại blog của anh ấy. Tôi đã sử dụng ast.parse để làm trình dịch Python-> JavaScript (@ https://bitbucket.org/amirouche/pythonium ). Tôi đã nghĩ ra thiết kế Pythonium bằng cách xem xét phần nào các triển khai khác và tự mình thử chúng. Tôi đã fork Pythonium từ https://github.com/PythonJS/PythonJS mà tôi cũng đã bắt đầu, Nó thực sự là một bản viết lại hoàn chỉnh. Thiết kế tổng thể được lấy cảm hứng từ PyPy và http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-89-1.pdf giấy.

Mọi thứ tôi đã thử, từ đầu đến giải pháp tốt nhất, ngay cả khi có vẻ như tiếp thị bằng Pythonium thì nó thực sự không phải như vậy (đừng ngần ngại cho tôi biết nếu có điều gì đó không đúng với cư dân mạng):

  • Triển khai ngữ nghĩa Python trong JavaScript cũ bằng cách sử dụng kế thừa nguyên mẫu: AFAIK không thể triển khai đa kế thừa Python bằng hệ thống đối tượng nguyên mẫu JS. Tôi đã cố gắng làm điều đó bằng các thủ thuật khác sau đó (xem getattribute). Theo như tôi biết không có triển khai đa kế thừa Python trong JavaScript, tốt nhất tồn tại là Single inhertance + mixin và tôi không chắc chúng xử lý kế thừa kim cương. Loại tương tự như Skulpt nhưng không có google clojure.

  • Tôi đã thử với Google clojure, giống như Skulpt (trình biên dịch) thay vì thực sự đọc mã Skulpt #fail. Dù sao vì hệ thống đối tượng dựa trên nguyên mẫu JS vẫn không thể. Việc tạo ràng buộc rất khó khăn, bạn cần phải viết JavaScript và rất nhiều mã soạn sẵn (xem https://github.com/skulpt/skulpt/issues/50 nơi tôi là con ma). Vào thời điểm đó, không có cách nào rõ ràng để tích hợp ràng buộc trong hệ thống xây dựng. Tôi nghĩ rằng Skulpt là một thư viện và bạn chỉ cần đưa các tệp .py của mình vào html để thực thi, không cần nhà phát triển thực hiện giai đoạn biên dịch nào.

  • Đã thử pyjaco (trình biên dịch) nhưng việc tạo liên kết (gọi mã Javascript từ mã Python) rất khó, có quá nhiều mã biên soạn sẵn để tạo mỗi lần. Bây giờ tôi nghĩ pyjaco là loài gần Pythonium hơn. pyjaco được viết bằng Python (cũng vậy) nhưng rất nhiều được viết bằng JavaScript và nó sử dụng kế thừa nguyên mẫu.

Tôi chưa bao giờ thực sự thành công khi chạy Pajamas #fail và chưa bao giờ cố đọc lại mã #fail. Nhưng trong tâm trí tôi, bộ đồ ngủ đang làm API-> API tranlation (hoặc framework sang framework) chứ không phải dịch từ Python sang JavaScript. Khung JavaScript sử dụng dữ liệu đã có trong trang hoặc dữ liệu từ máy chủ. Mã Python chỉ là "hệ thống ống nước". Sau đó, tôi phát hiện ra rằng bộ đồ ngủ thực sự là một con trăn thật-> js phiên dịch.

Tôi vẫn nghĩ rằng có thể thực hiện dịch API-> API (hoặc framework-> framework) và về cơ bản đó là những gì tôi làm trong Pythonium nhưng ở cấp thấp hơn. Có lẽ Pyjama sử dụng thuật toán tương tự như Pythonium ...

Sau đó, tôi phát hiện ra brython được viết hoàn toàn bằng Javascript như Skulpt, không cần biên dịch và nhiều lông tơ ... mà được viết bằng JavaScript.

Kể từ dòng đầu tiên được viết trong quá trình của dự án này, tôi đã biết về PyPy, thậm chí là phần phụ trợ JavaScript cho PyPy. Đúng vậy, nếu tìm thấy, bạn có thể tạo trực tiếp trình thông dịch Python bằng JavaScript từ PyPy. Mọi người nói, đó là một thảm họa. Tôi đọc không hiểu tại sao. Nhưng tôi nghĩ lý do là ngôn ngữ trung gian mà họ sử dụng để triển khai trình thông dịch, RPython, là một tập con của Python được điều chỉnh để dịch sang C (và có thể là asm). Ira Baxter nói rằng bạn luôn đặt ra các giả định khi xây dựng một thứ gì đó và có lẽ bạn đã tinh chỉnh nó sao cho phù hợp nhất với những gì nó cần làm trong trường hợp bản dịch PyPy: Python-> C. Những giả định đó có thể không phù hợp trong một bối cảnh khác, tệ hơn là chúng có thể suy diễn ra chi phí nếu không nói rằng bản dịch trực tiếp rất có thể sẽ luôn tốt hơn.

Có trình thông dịch được viết bằng Python có vẻ là một ý tưởng (rất) hay. Nhưng tôi quan tâm nhiều hơn đến một trình biên dịch vì lý do hiệu suất, nó thực sự dễ dàng hơn để biên dịch Python sang JavaScript hơn là diễn giải nó.

Tôi bắt đầu PythonJS với ý tưởng tập hợp một tập con Python mà tôi có thể dễ dàng dịch sang JavaScript. Lúc đầu, tôi thậm chí không bận tâm đến việc triển khai hệ thống OO vì kinh nghiệm trong quá khứ. Tập hợp con của Python mà tôi đã đạt được để dịch sang JavaScript là:

  • hàm với đầy đủ các tham số ngữ nghĩa cả trong định nghĩa và cách gọi. Đây là phần tôi tự hào nhất.
  • while / if / elif / else
  • Các loại Python đã được chuyển đổi thành các loại JavaScript (không có bất kỳ loại python nào)
  • for có thể lặp lại chỉ trên các mảng Javascript (đối với một trong mảng)
  • Truy cập minh bạch vào JavaScript: nếu bạn viết Mảng bằng mã Python, nó sẽ được dịch sang Mảng trong javascript. Đây là thành tựu lớn nhất về khả năng sử dụng so với các đối thủ cạnh tranh.
  • Bạn có thể chuyển hàm được định nghĩa trong nguồn Python sang các hàm javascript. Các đối số mặc định sẽ được tính đến.
  • Nó bổ sung có chức năng đặc biệt gọi là new được dịch sang JavaScript mới, ví dụ: new (Python) (1, 2, spam, "egg") được dịch thành "new Python (1, 2, spam," egg ").
  • "var" được trình dịch tự động xử lý. (phát hiện rất hay từ Brett (cộng tác viên PythonJS).
  • từ khóa toàn cầu
  • đóng cửa
  • lambdas
  • danh sách hiểu
  • nhập khẩu được hỗ trợ thông qua requestjs
  • kế thừa lớp đơn + mixin qua Classjs

Điều này có vẻ như rất nhiều nhưng thực sự rất hẹp so với ngữ nghĩa đầy đủ của Python. Nó thực sự là JavaScript với cú pháp Python.

JS được tạo ra là hoàn hảo tức là. không có chi phí chung, nó không thể được cải thiện về mặt hiệu suất bằng cách chỉnh sửa thêm. Nếu bạn có thể cải thiện mã được tạo, bạn cũng có thể làm điều đó từ tệp nguồn Python. Ngoài ra, trình biên dịch không dựa vào bất kỳ thủ thuật JS nào mà bạn có thể tìm thấy trong .js được viết bởi http://superherojs.com/ , vì vậy nó rất dễ đọc.

Hậu duệ trực tiếp của phần này của PythonJS là chế độ Pythonium Veloce. Bạn có thể tìm thấy toàn bộ cách triển khai @ https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/veloce/veloce.py?at=master 793 SLOC + khoảng 100 SLOC mã được chia sẻ với người dịch khác.

Có thể dịch phiên bản thích nghi của pystone.py ở chế độ Veloce cf. https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pystone/?at=master

Sau khi thiết lập bản dịch Python-> JavaScript cơ bản, tôi đã chọn một đường dẫn khác để dịch Python đầy đủ sang JavaScript. Cách glib thực hiện mã dựa trên lớp hướng đối tượng ngoại trừ ngôn ngữ đích là JS nên bạn có quyền truy cập vào các mảng, các đối tượng giống bản đồ và nhiều thủ thuật khác và tất cả phần đó được viết bằng Python. IIRC không có mã javascript được viết bởi trình dịch Pythonium. Nhận thừa kế đơn lẻ không khó đây là những phần khó khăn khiến Pythonium hoàn toàn tuân thủ với Python:

  • spam.egg trong Python luôn được dịch sang getattribute(spam, "egg") Tôi không nêu cụ thể điều này nhưng tôi nghĩ rằng nó mất rất nhiều thời gian và tôi không chắc mình có thể cải thiện nó với asm.js hoặc bất cứ thứ gì khác.
  • thứ tự phân giải phương thức: ngay cả với thuật toán được viết bằng Python, việc dịch nó sang mã tương thích Python Veloce là một nỗ lực lớn.
  • getattributre : thuật toán phân giải getattribute thực tế khá phức tạp và nó vẫn không hỗ trợ bộ mô tả dữ liệu
  • dựa trên lớp metaclass: Tôi biết nơi cắm mã, nhưng vẫn ...
  • cuối cùng không kém phần quan trọng: some_callable (...) luôn được chuyển thành "call (some_callable)". AFAIK trình dịch hoàn toàn không sử dụng suy luận, vì vậy mỗi khi bạn thực hiện một cuộc gọi, bạn cần phải kiểm tra loại đối tượng nào để gọi nó theo cách mà nó được gọi.

Phần này được tính trong https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/runtime.py?at=master Phần này được viết bằng Python tương thích với Python Veloce.

Trình biên dịch tuân thủ thực tế https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/compliant.py?at=master không tạo mã JavaScript trực tiếp và quan trọng nhất là không thực hiện chuyển đổi ast-> ast . Tôi đã thử điều ast-> và ast ngay cả khi đẹp hơn cst cũng không tốt khi làm việc với ngay cả với ast.NodeTransformer và quan trọng hơn là tôi không cần phải làm ast-> ast.

Làm từ python ast sang python ast trong trường hợp của tôi ít nhất có thể là một sự cải thiện hiệu suất vì đôi khi tôi kiểm tra nội dung của một khối trước khi tạo mã được liên kết với nó, ví dụ:

  • var / global: để có thể var một cái gì đó, tôi phải biết những gì tôi cần và không nên var. Thay vì tạo khối theo dõi biến nào được tạo trong một khối nhất định và chèn nó lên trên khối chức năng đã tạo, tôi chỉ tìm cách gán biến mới khi nhập khối trước khi thực sự truy cập vào nút con để tạo mã liên kết.
  • Năng suất, trình tạo có cú pháp đặc biệt trong JS, vì vậy tôi cần biết hàm Python nào là trình tạo khi tôi muốn viết "var my_generator = function"

Vì vậy, tôi không thực sự truy cập từng nút một lần cho mỗi giai đoạn của bản dịch.

Quá trình tổng thể có thể được mô tả như sau:

Python source code -> Python ast -> Python source code compatible with Veloce mode -> Python ast -> JavaScript source code

Nội trang Python được viết bằng mã Python (!), IIRC có một vài hạn chế liên quan đến các kiểu khởi động, nhưng bạn có quyền truy cập vào mọi thứ có thể dịch Pythonium ở chế độ tuân thủ. Hãy xem tại https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/builtins/?at=master

Có thể hiểu được việc đọc mã JS được tạo từ tuân thủ pythonium nhưng bản đồ nguồn sẽ giúp ích rất nhiều.

Lời khuyên có giá trị mà tôi có thể cung cấp cho bạn dựa trên kinh nghiệm này là những con rắm già:

  • đánh giá sâu rộng chủ đề cả trong văn học và các dự án hiện có nguồn đóng hoặc miễn phí. Khi tôi xem xét các dự án hiện có khác nhau, tôi lẽ ra nên cho nó nhiều thời gian và động lực hơn.
  • hỏi câu hỏi! Nếu tôi biết trước rằng chương trình phụ trợ PyPy vô dụng vì chi phí cao do không khớp ngữ nghĩa C / Javascript. Tôi có thể đã có ý tưởng Pythonium cách đây 6 tháng có thể là 3 năm trước.
  • biết bạn muốn làm gì, có mục tiêu. Đối với dự án này, tôi có các mục tiêu khác nhau: thực hành một chút javascript, tìm hiểu thêm về Python và có thể viết mã Python sẽ chạy trong trình duyệt (hơn thế nữa bên dưới).
  • thất bại là kinh nghiệm
  • một bước nhỏ là một bước
  • khởi đầu nhỏ
  • ước mơ lớn
  • làm bản demo
  • lặp lại

Chỉ với chế độ Python Veloce, tôi rất vui! Nhưng trên đường đi, tôi phát hiện ra rằng những gì tôi thực sự đang tìm kiếm là giải phóng tôi và những người khác khỏi Javascript nhưng quan trọng hơn là có thể tạo ra một cách thoải mái. Điều này dẫn tôi đến Đề án, DSL, Mô hình và cuối cùng là các mô hình miền cụ thể (xem http://dsmforum.org/ ).

Về phản ứng của Ira Baxter:

Các ước tính không hữu ích ở tất cả. Tôi đã dành cho tôi ít hơn 6 tháng thời gian rảnh cho cả PythonJS và Pythonium. Vì vậy, tôi có thể mong đợi nhiều hơn từ toàn thời gian 6 tháng. Tôi nghĩ tất cả chúng ta đều biết 100 năm trong bối cảnh doanh nghiệp có thể có ý nghĩa và không có nghĩa gì cả ...

Khi ai đó nói điều gì đó khó hoặc thường là không thể, tôi trả lời rằng "chỉ mất thời gian để tìm ra giải pháp cho một vấn đề không thể" nói cách khác không có gì là không thể ngoại trừ nếu nó được chứng minh là không thể trong trường hợp này là một bằng chứng toán học ...

Nếu nó không được chứng minh là không thể thì nó sẽ dành chỗ cho trí tưởng tượng:

  • tìm một bằng chứng chứng minh điều đó là không thể

  • Nếu không thể có một vấn đề "thấp kém" có thể có một giải pháp.

hoặc là

  • nếu nó không phải là không thể, tìm một giải pháp

Đó không chỉ là suy nghĩ lạc quan. Khi tôi bắt đầu Python-> Javascript, mọi người đều nói rằng điều đó là không thể. PyPy không thể. Kính đeo quá khó. vv ... Tôi nghĩ rằng cuộc cách mạng duy nhất đưa PyPy vượt qua giấy Scheme-> C (đã 25 tuổi) là một số thế hệ JIT tự động (các gợi ý dựa trên được viết trong trình thông dịch RPython mà tôi nghĩ).

Hầu hết những người nói rằng một việc là "khó" hoặc "không thể" đều không cung cấp lý do. C ++ khó phân tích cú pháp? Tôi biết rằng, chúng vẫn là trình phân tích cú pháp C ++ (miễn phí). Cái ác là chi tiết? Tôi biết điều đó. Nói điều đó không thể một mình không có ích gì, Điều tồi tệ hơn là "không hữu ích" là nó làm nản lòng và một số người có ý làm nản lòng người khác. Tôi đã nghe về câu hỏi này qua /programming/22621164/how-to-automatically-generate-a-parser-code-to-code-translator-from-a-corpus .

Điều gì sẽ là sự hoàn hảo cho bạn ? Đó là cách bạn xác định mục tiêu tiếp theo và có thể đạt được mục tiêu tổng thể.

Tôi quan tâm hơn đến việc biết những loại mẫu nào tôi có thể thực thi trên mã để giúp dịch mã dễ dàng hơn (ví dụ: IoC, SOA?) Mã hơn là cách thực hiện dịch.

Tôi thấy không có mẫu nào không thể dịch từ ngôn ngữ này sang ngôn ngữ khác ít nhất là theo cách kém hoàn hảo. Vì có thể dịch từ ngôn ngữ sang ngôn ngữ khác, nên bạn nên nhắm mục tiêu này trước. Vì, tôi nghĩ theo http://en.wikipedia.org/wiki/Graph_isomorphism_problem , bản dịch giữa hai ngôn ngữ máy tính là dạng cây hoặc đẳng cấu DAG. Ngay cả khi chúng ta đã biết rằng cả hai đều hoàn chỉnh, vì vậy ...

Framework-> Framework mà tôi hình dung rõ hơn là API-> Bản dịch API vẫn có thể là thứ mà bạn có thể lưu ý như một cách để cải thiện mã đã tạo. Ví dụ: Prolog dưới dạng cú pháp rất cụ thể nhưng bạn vẫn có thể làm Prolog như tính toán bằng cách mô tả cùng một đồ thị trong Python ... Nếu tôi triển khai một trình dịch Prolog sang Python, tôi sẽ không thực hiện hợp nhất trong Python mà trong thư viện C và đến đưa ra một "cú pháp Python" rất dễ đọc đối với một Pythonist. Cuối cùng, cú pháp chỉ là "bức tranh" mà chúng ta đưa ra một ý nghĩa (đó là lý do tại sao tôi bắt đầu lược đồ). Cái ác nằm ở chi tiết của ngôn ngữ và tôi không nói về cú pháp. Các khái niệm được sử dụng trong ngôn ngữ getattributehook (bạn có thể sống mà không có nó) nhưng các tính năng VM cần thiết như tối ưu hóa đệ quy đuôi có thể khó xử lý. Bạn không quan tâm nếu chương trình ban đầu không sử dụng đệ quy đuôi và ngay cả khi không có đệ quy đuôi trong ngôn ngữ đích, bạn có thể mô phỏng nó bằng cách sử dụng vòng lặp sự kiện / greenlets.

Đối với ngôn ngữ đích và ngôn ngữ nguồn, hãy tìm:

  • Ý tưởng lớn và cụ thể
  • Những ý tưởng nhỏ và chung được chia sẻ

Từ điều này sẽ xuất hiện:

  • Những thứ dễ dịch
  • Những thứ khó dịch

Bạn cũng có thể biết những gì sẽ được dịch sang mã nhanh và chậm.

Ngoài ra còn có câu hỏi của stdlib hoặc bất kỳ thư viện nhưng không có câu trả lời rõ ràng, nó phụ thuộc vào mục tiêu của bạn.

Mã tự động hoặc mã được tạo có thể đọc được cũng có các giải pháp ...

Nhắm mục tiêu một nền tảng như PHP dễ dàng hơn nhiều so với nhắm mục tiêu trình duyệt vì bạn có thể cung cấp triển khai C của đường dẫn chậm và / hoặc quan trọng.

Với dự án đầu tiên của bạn là dịch Python sang PHP, ít nhất là đối với tập con PHP3 mà tôi biết, tùy chỉnh veloce.py là lựa chọn tốt nhất của bạn. Nếu bạn có thể triển khai veloce.py cho PHP thì có lẽ bạn sẽ có thể chạy chế độ tuân thủ ... Ngoài ra, nếu bạn có thể dịch PHP sang tập hợp con của PHP, bạn có thể tạo bằng php_veloce.py điều đó có nghĩa là bạn có thể dịch PHP sang tập con của Python mà veloce.py có thể sử dụng, điều đó có nghĩa là bạn có thể dịch PHP sang Javascript. Chỉ nói ...

Bạn cũng có thể xem các thư viện đó:

Ngoài ra, bạn có thể quan tâm đến bài đăng trên blog này (và nhận xét): https://www.rfk.id.au/blog/entry/pypy-js-poc-jit/


Điều duy nhất mà cốt ly kỳ cho tôi nghe về một-một ngôn ngữ máy tính để dịch ngôn ngữ máy tính được mô tả trong stackoverflow.com/questions/22621164/...
amirouche

Tôi thứ hai câu trả lời khác về kiểu dữ liệu. Trong Pythonium, tôi thậm chí còn không có kế hoạch hỗ trợ một số nguyên & kiểu float chính xác trong chế độ tuân thủ mà không có asm.js.
amirouche

Được rồi, vậy nếu tôi cung cấp cho bạn một gói Python 100K SLOC và bạn chạy nó thông qua "trình dịch" của mình, thì tôi có nhận được một chương trình làm việc không? Cần bao nhiêu công việc thủ công sau khi dịch để sửa chữa nó? Những gì bạn nói ở đây là, "được cung cấp một trình phân tích cú pháp tốt đã có sẵn cho Python để xây dựng AST, tôi có thể xây dựng một bộ dịch một phần trong 6 tháng". Không ai ngạc nhiên. 6 tháng theo tiêu chuẩn của hầu hết mọi người không phải là "dễ dàng" (trích dẫn từ một nhận xét khác của bạn). Giải quyết các vấn đề còn lại sẽ đòi hỏi nhiều nỗ lực hơn. Câu trả lời của tôi nói, về cơ bản "làm điều này không dễ dàng", và "làm theo cách nói chung là khó".
Ira Baxter

... điểm cuối cùng đáp lại mong muốn ban đầu của OP: "lý tưởng nhất là tôi có thể thêm các ngôn ngữ khác một cách dễ dàng (tương đối).", câu trả lời của tôi đề cập cụ thể.
Ira Baxter

Tôi xin phép không đồng ý, đặc biệt là khi bạn biết mình đang làm gì, điều đó thật dễ dàng và những gì tiếp theo không khó, chỉ là vấn đề hoàn thành công việc. Tôi không chắc bạn đang giải quyết bất cứ điều gì cụ thể cho câu hỏi ở đâu. Bạn đang nói trong đoạn văn 4 hoặc 5 rằng công ty của bạn làm được điều đó, và thật khó. Nhưng nếu không, bạn đang truyền bá FUD về chủ đề này, trong khi hơi lạc đề như bạn đang ở trong stackoverflow.com/questions/22621164/… . Trong toàn bộ thời gian 6 tháng, tôi sẽ viết một dịch giả đầy đủ.
amirouche

0

Bạn có thể xem qua trình biên dịch Vala , dịch Vala (một ngôn ngữ giống C #) sang C.


Mục tiêu thiết kế của Vala là được dịch sang C và làm cho việc phát triển với các thư viện gnome trở nên dễ dàng.
amirouche
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.