Hướng dẫn what is used for parsing and running javascript in nodejs - những gì được sử dụng để phân tích cú pháp và chạy javascript trong nodejs

Đây là một bài viết tương tự như một bài viết trước đây chúng tôi đã viết: phân tích cú pháp trong Java, vì vậy phần giới thiệu là như nhau. Bỏ qua Chương 3 nếu bạn đã đọc nó.

Nếu bạn cần phân tích ngôn ngữ hoặc tài liệu, từ JavaScript, về cơ bản có ba cách để giải quyết vấn đề:

  • Sử dụng thư viện hiện có hỗ trợ ngôn ngữ cụ thể đó: ví dụ: thư viện để phân tích cú pháp XML
  • Xây dựng trình phân tích cú pháp tùy chỉnh của riêng bạn bằng tay
  • một công cụ hoặc thư viện để tạo trình phân tích cú pháp: ví dụ: antlr, bạn có thể sử dụng để xây dựng trình phân tích cú pháp cho bất kỳ ngôn ngữ nào

Phân tích cú pháp: Công cụ và thư viện

Nhận hướng dẫn cho hộp thư đến của bạn để đọc nó trên tất cả các thiết bị của bạn khi bạn có thời gian. Tìm hiểu về phân tích cú pháp trong Java, Python, C#và JavaScript

Sử dụng một thư viện hiện có

Tùy chọn đầu tiên là tốt nhất cho các ngôn ngữ nổi tiếng và được hỗ trợ, như XML hoặc HTML. Một thư viện tốt thường bao gồm API cũng để xây dựng và sửa đổi các tài liệu theo lập trình bằng ngôn ngữ đó. Đây thường là nhiều hơn những gì bạn nhận được từ một trình phân tích cú pháp cơ bản. Vấn đề là các thư viện như vậy không quá phổ biến và chúng chỉ hỗ trợ các ngôn ngữ phổ biến nhất. Trong các trường hợp khác, bạn đã hết may mắn.

Xây dựng trình phân tích cú pháp tùy chỉnh của riêng bạn bằng tay

Bạn có thể cần chọn tùy chọn thứ hai nếu bạn có nhu cầu cụ thể. Cả hai theo nghĩa là ngôn ngữ bạn cần phân tích cú pháp không thể được phân tích cú pháp với trình tạo trình phân tích cú pháp truyền thống hoặc bạn có các yêu cầu cụ thể mà bạn không thể đáp ứng khi sử dụng trình tạo trình phân tích cú pháp điển hình. Chẳng hạn, vì bạn cần hiệu suất tốt nhất có thể hoặc tích hợp sâu giữa các thành phần khác nhau.

Một công cụ hoặc thư viện để tạo trình phân tích cú pháp

Trong tất cả các trường hợp khác, tùy chọn thứ ba phải là lựa chọn mặc định, bởi vì là lựa chọn linh hoạt nhất và có thời gian phát triển ngắn hơn. Đó là lý do tại sao trên bài viết này, chúng tôi tập trung vào các công cụ và thư viện tương ứng với tùy chọn này.

Lưu ý: Văn bản trong blockquote mô tả một chương trình đến từ tài liệu tương ứng

Chúng ta sẽ xem:

  • Các công cụ có thể tạo ra các trình phân tích cú pháp có thể sử dụng từ JavaScript [và có thể từ các ngôn ngữ khác]
  • Thư viện JavaScript để xây dựng trình phân tích cú pháp

Các công cụ có thể được sử dụng để tạo mã cho trình phân tích cú pháp được gọi là trình tạo phân tích cú pháp hoặc trình biên dịch trình biên dịch. Các thư viện tạo trình phân tích cú pháp được gọi là bộ phân tích phân tích cú pháp.parser generators or compiler compiler. Libraries that create parsers are known as parser combinators.

Trình tạo trình phân tích cú pháp [hoặc bộ phân tích phân tích cú pháp] không tầm thường: Bạn cần một chút thời gian để tìm hiểu cách sử dụng chúng và không phải tất cả các loại trình tạo trình phân tích cú pháp đều phù hợp với tất cả các loại ngôn ngữ. Đó là lý do tại sao chúng tôi đã chuẩn bị một danh sách những người nổi tiếng nhất trong số họ, với phần giới thiệu ngắn cho mỗi người trong số họ. Chúng tôi cũng đang tập trung vào một ngôn ngữ mục tiêu: JavaScript. Điều này cũng có nghĩa là [thông thường] bản thân trình phân tích cú pháp sẽ được viết bằng JavaScript.

Để liệt kê tất cả các công cụ và thư viện có thể phân tích cú pháp cho tất cả các ngôn ngữ sẽ rất thú vị, nhưng không hữu ích. Đó là bởi vì sẽ có quá nhiều lựa chọn đơn giản và tất cả chúng ta sẽ bị lạc trong chúng. Bằng cách tập trung vào một ngôn ngữ lập trình, chúng tôi có thể cung cấp một so sánh táo với táo và giúp bạn chọn một tùy chọn cho dự án của mình.

Những điều hữu ích để biết về trình phân tích cú pháp

Để đảm bảo rằng danh sách này có thể truy cập được cho tất cả các lập trình viên, chúng tôi đã chuẩn bị một lời giải thích ngắn cho các thuật ngữ và khái niệm mà bạn có thể gặp phải khi tìm kiếm trình phân tích cú pháp. Chúng tôi không cố gắng cung cấp cho bạn những lời giải thích chính thức, nhưng thực tế.

Cấu trúc của trình phân tích cú pháp

Một trình phân tích cú pháp thường bao gồm hai phần: Lexer, còn được gọi là máy quét hoặc tokenizer và trình phân tích cú pháp thích hợp. Không phải tất cả các trình phân tích cú pháp đều áp dụng lược đồ hai bước này: một số trình phân tích cú pháp không phụ thuộc vào Lexer. Chúng được gọi là trình phân tích cú pháp không quét.

Lexer và trình phân tích cú pháp hoạt động theo trình tự: Lexer quét đầu vào và tạo ra các mã thông báo phù hợp, trình phân tích cú pháp quét các mã thông báo và tạo ra kết quả phân tích cú pháp.

Hãy cùng nhìn vào ví dụ sau đây và tưởng tượng rằng chúng ta đang cố gắng phân tích một hoạt động toán học.

437 + 734

Lexer quét văn bản và tìm ‘4,‘ 3, ‘7, và sau đó là không gian‘. Công việc của Lexer là nhận ra rằng các ký tự đầu tiên tạo thành một mã thông báo của loại num. Sau đó, Lexer tìm thấy biểu tượng ‘+, tương ứng với mã thông báo thứ hai của loại Plus và cuối cùng nó tìm thấy một mã thông báo khác của loại num.

Trình phân tích cú pháp thường sẽ kết hợp các mã thông báo được sản xuất bởi Lexer và nhóm chúng.

Các định nghĩa được sử dụng bởi Lexers hoặc trình phân tích cú pháp được gọi là quy tắc hoặc sản xuất. Quy tắc Lexer sẽ chỉ định rằng một chuỗi các chữ số tương ứng với một mã thông báo loại num, trong khi quy tắc phân tích cú pháp sẽ chỉ định rằng một chuỗi các mã thông báo loại num, cộng với, NUM tương ứng với một biểu thức.

Trình phân tích cú pháp không quét là khác nhau vì chúng xử lý trực tiếp văn bản gốc, thay vì xử lý một danh sách các mã thông báo được tạo bởi một Lexer. are different because they process directly the original text, instead of processing a list of tokens produced by a lexer.

Bây giờ là điển hình để tìm các bộ có thể tạo ra cả Lexer và trình phân tích cú pháp. Trước đây, thay vào đó là kết hợp hai công cụ khác nhau: một để tạo ra Lexer và một để tạo ra trình phân tích cú pháp. Đây là ví dụ như trường hợp của cặp vợ chồng Lex & Yacc đáng kính: Lex sản xuất Lexer, trong khi YACC sản xuất trình phân tích cú pháp.

Cây phân tích và cây cú pháp trừu tượng

Có hai thuật ngữ có liên quan và đôi khi chúng được sử dụng thay thế cho nhau: parse cây và cú pháp trừu tượng [AST].

Về mặt khái niệm, chúng rất giống nhau:

  • Cả hai đều là cây: có một gốc đại diện cho toàn bộ đoạn mã được phân tích cú pháp. Sau đó, có những người con nhỏ hơn đại diện cho các phần mã trở nên nhỏ hơn cho đến khi các mã thông báo đơn xuất hiện trong câytrees: there is a root representing the whole piece of code parsed. Then there are smaller subtrees representing portions of code that become smaller until single tokens appear in the tree
  • Sự khác biệt là mức độ trừu tượng: cây Parse chứa tất cả các mã thông báo xuất hiện trong chương trình và có thể là một tập hợp các quy tắc trung gian. Thay vào đó, AST là một phiên bản đánh bóng của cây phân tích.

Trong AST, một số thông tin bị mất, ví dụ như nhận xét và nhóm các ký hiệu [dấu ngoặc đơn] không được trình bày. Những thứ như bình luận là thừa cho một chương trình và các biểu tượng nhóm được xác định ngầm bởi cấu trúc của cây.

Một cây phân tích là một đại diện của mã gần hơn với cú pháp cụ thể. Nó cho thấy nhiều chi tiết về việc thực hiện trình phân tích cú pháp. Chẳng hạn, thường là một quy tắc tương ứng với loại nút. Một cây phân tích thường được người dùng chuyển đổi trong AST, có thể với một số trợ giúp từ trình tạo trình phân tích cú pháp.

Một đại diện đồ họa của một AST trông như thế này.

Đôi khi bạn có thể muốn bắt đầu sản xuất một cây phân tích và sau đó xuất phát từ nó một AST. Điều này có thể có ý nghĩa bởi vì cây phân tích dễ dàng sản xuất cho trình phân tích cú pháp [đó là biểu diễn trực tiếp của quá trình phân tích cú pháp] nhưng AST đơn giản và dễ xử lý hơn theo các bước sau. Theo các bước sau, chúng tôi có nghĩa là tất cả các hoạt động mà bạn có thể muốn thực hiện trên cây: xác thực mã, giải thích, biên dịch, v.v.

Văn phạm

Ngữ pháp là một mô tả chính thức về một ngôn ngữ có thể được sử dụng để nhận ra cấu trúc của nó.

Nói một cách đơn giản là một danh sách các quy tắc xác định cách mỗi cấu trúc có thể được sáng tác. Ví dụ, một quy tắc cho một câu lệnh IF có thể chỉ định rằng nó phải bắt đầu với từ khóa của IF IF, theo sau là dấu ngoặc đơn bên trái, biểu thức, dấu ngoặc đơn bên phải và một câu lệnh.

Một quy tắc có thể tham chiếu các quy tắc hoặc loại mã thông báo khác. Trong ví dụ về câu lệnh IF, từ khóa, If If, bên trái và dấu ngoặc đơn bên phải là các loại mã thông báo, trong khi biểu thức và câu lệnh là các tham chiếu đến các quy tắc khác.

Định dạng được sử dụng nhiều nhất để mô tả các ngữ pháp là dạng Backus-Naur [BNF], cũng có nhiều biến thể, bao gồm cả dạng backus-maur mở rộng. Biến thể mở rộng có lợi thế bao gồm một cách đơn giản để biểu thị sự lặp lại. Một quy tắc điển hình trong ngữ pháp backus-naur trông như thế này:Backus-Naur Form [BNF], which also has many variants, including the Extended Backus-Naur Form. The Extended variant has the advantage of including a simple way to denote repetitions. A typical rule in a Backus-Naur grammar looks like this:

 ::= __expression__

 ::= __expression__
9 thường là phi terminal, có nghĩa là nó có thể được thay thế bằng nhóm các phần tử ở bên phải,
addition       ::= expression '+' expression
multiplication ::= expression '*' expression
// an expression could be an addition or a multiplication or a number
expression     ::= addition | multiplication |// a number
0. Yếu tố
addition       ::= expression '+' expression
multiplication ::= expression '*' expression
// an expression could be an addition or a multiplication or a number
expression     ::= addition | multiplication |// a number
0 có thể chứa các ký hiệu hoặc thiết bị đầu cuối khác. Các biểu tượng thiết bị đầu cuối chỉ đơn giản là các biểu tượng không xuất hiện dưới dạng
 ::= __expression__
9 bất cứ nơi nào trong ngữ pháp. Một ví dụ điển hình về biểu tượng thiết bị đầu cuối là một chuỗi các ký tự, như lớp lớp.

Quy tắc thu hồi trái

Trong bối cảnh của các trình phân tích cú pháp, một tính năng quan trọng là sự hỗ trợ cho các quy tắc thu hồi trái. Điều này có nghĩa là một quy tắc có thể bắt đầu với một tham chiếu đến chính nó. Tài liệu tham khảo này cũng có thể là gián tiếp.

Xem xét ví dụ các hoạt động số học. Một bổ sung có thể được mô tả là hai [các] biểu thức được phân tách bằng ký hiệu cộng [+], nhưng một biểu thức cũng có thể chứa các bổ sung khác.

addition       ::= expression '+' expression
multiplication ::= expression '*' expression
// an expression could be an addition or a multiplication or a number
expression     ::= addition | multiplication |// a number

Mô tả này cũng phù hợp với nhiều bổ sung như 5 + 4 + 3. Đó là bởi vì nó có thể được hiểu là biểu thức biểu thức [5] [‘ +,] [4 + 3]. Và sau đó 4 + 3 có thể được chia trong hai thành phần của nó.

Vấn đề là loại quy tắc này có thể không được sử dụng với một số trình tạo trình phân tích cú pháp. Giải pháp thay thế là một chuỗi dài các biểu thức cũng chăm sóc sự ưu tiên của các nhà khai thác.

Một số trình tạo trình phân tích cú pháp hỗ trợ các quy tắc tái tạo trái trực tiếp, nhưng không gián tiếp.

Các loại ngôn ngữ và ngữ pháp

Chúng tôi quan tâm chủ yếu là khoảng hai loại ngôn ngữ có thể được phân tích cú pháp với trình tạo trình phân tích cú pháp: ngôn ngữ thông thường và ngôn ngữ không có ngữ cảnh. Chúng tôi có thể cung cấp cho bạn định nghĩa chính thức theo hệ thống phân cấp ngôn ngữ Chomsky, nhưng nó sẽ không hữu ích. Thay vào đó, hãy nhìn vào một số khía cạnh thực tế.

Một ngôn ngữ thông thường có thể được xác định bởi một loạt các biểu thức thông thường, trong khi một ngôn ngữ không có ngữ cảnh cần một cái gì đó nhiều hơn. Một quy tắc đơn giản là nếu một ngữ pháp của một ngôn ngữ có các yếu tố đệ quy thì nó không phải là ngôn ngữ thông thường. Chẳng hạn, như chúng ta đã nói ở nơi khác, HTML không phải là ngôn ngữ thông thường. Trong thực tế, hầu hết các ngôn ngữ lập trình là các ngôn ngữ không có ngữ cảnh.

Thông thường với một loại ngôn ngữ tương ứng cùng một loại ngữ pháp. Điều đó có nghĩa là có các ngữ pháp thường xuyên và các ngữ pháp không có ngữ cảnh tương ứng với các ngôn ngữ thông thường và không có ngữ cảnh. Nhưng để làm phức tạp các vấn đề, có một loại ngữ pháp tương đối mới [được tạo ra trong năm 2004], được gọi là ngữ pháp biểu thức phân tích cú pháp [PEG]. Những ngữ pháp này mạnh mẽ như các ngữ pháp không có ngữ cảnh, nhưng theo các tác giả của họ, họ mô tả các ngôn ngữ lập trình một cách tự nhiên hơn.

Sự khác biệt giữa PEG và CFG

Sự khác biệt chính giữa PEG và CFG là thứ tự các lựa chọn có ý nghĩa trong PEG, nhưng không phải trong CFG. Nếu có nhiều cách hợp lệ có thể để phân tích đầu vào, CFG sẽ mơ hồ và do đó sai. Thay vào đó với PEG, sự lựa chọn áp dụng đầu tiên sẽ được chọn và điều này tự động giải quyết một số sự mơ hồ.

Một điểm khác biệt khác là các trình phân tích cú pháp không sử dụng PEG sử dụng: họ không cần một giai đoạn phân tích từ vựng hoặc từ vựng riêng biệt.

Theo truyền thống, cả PEG và một số CFG đều không thể đối phó với các quy tắc thu hồi trái, nhưng một số công cụ đã tìm thấy cách giải quyết cho việc này. Bằng cách sửa đổi thuật toán phân tích cú pháp cơ bản hoặc bằng cách tự động viết lại quy tắc tái tạo trái theo cách không đệ quy. Một trong những cách này có nhược điểm: bằng cách làm cho trình phân tích cú pháp được tạo trở nên dễ hiểu hơn hoặc làm xấu đi hiệu suất của nó. Tuy nhiên, về mặt thực tế, những lợi thế của sự phát triển dễ dàng và nhanh hơn vượt quá những nhược điểm.

Nếu bạn muốn biết thêm về lý thuyết phân tích cú pháp, bạn nên đọc một hướng dẫn để phân tích cú pháp: thuật toán và thuật ngữ.A Guide to Parsing: Algorithms and Terminology.

Máy phát điện phân tích cú pháp

Quy trình công việc cơ bản của công cụ Trình tạo trình phân tích cú pháp khá đơn giản: bạn viết một ngữ pháp xác định ngôn ngữ hoặc tài liệu và bạn chạy công cụ để tạo trình phân tích cú pháp có thể sử dụng từ mã JavaScript của bạn.

Trình phân tích cú pháp có thể tạo ra AST, rằng bạn có thể phải đi qua chính mình hoặc bạn có thể đi qua các lớp sẵn sàng bổ sung, người nghe hoặc khách truy cập như vậy. Thay vào đó, một số công cụ cung cấp cơ hội nhúng mã bên trong ngữ pháp để được thực thi mỗi khi quy tắc cụ thể được khớp.

Thông thường bạn cần một thư viện thời gian chạy và/hoặc chương trình để sử dụng trình phân tích cú pháp được tạo.

Thường xuyên [Lexer]

Các công cụ phân tích các ngôn ngữ thông thường thường được gọi là từ vựng.

Lexer

Lexer là một Lexer tuyên bố sẽ được mô hình hóa sau Flex. Mặc dù một mô tả công bằng hơn sẽ là một Lexer ngắn dựa trên

addition       ::= expression '+' expression
multiplication ::= expression '*' expression
// an expression could be an addition or a multiplication or a number
expression     ::= addition | multiplication |// a number
3. Tài liệu có vẻ tối thiểu, chỉ với một vài ví dụ, nhưng toàn bộ là 147 dòng mã, vì vậy nó thực sự toàn diện.

Tuy nhiên, trong một vài dòng quản lý để hỗ trợ một vài điều thú vị và nó dường như khá phổ biến và dễ sử dụng. Một điều là hỗ trợ Ringojs, một nền tảng JavaScript trên đỉnh của JVM. Một cái khác là sự tích hợp với Jison, bản sao Bison trong JavaScript. Nếu bạn tiết chế kỳ vọng của bạn, nó có thể là một công cụ hữu ích.

Không có ngữ pháp, bạn chỉ sử dụng một hàm để xác định mẫu regexp và hành động cần được thực thi khi mẫu được khớp. Vì vậy, nó là sự giao thoa giữa một trình tạo Lexer và một bộ kết hợp Lexer. Bạn không thể kết hợp các hàm Lexer khác nhau, như trong một bộ kết hợp Lexer, nhưng nó chỉ được tạo động trong thời gian chạy, vì vậy nó cũng không phải là trình tạo Lexer thích hợp.

var lexer = new Lexer;

var chars = lines = 0;

lexer.addRule[/n/, function [] {
    lines++;
    chars++;
}];
    
lexer.addRule[/./, function [] {
    chars++;
}];
    
lexer.setInput["Hello World!n Hello Stars!n!"]
    
lexer.lex[];

Bối cảnh miễn phí

Hãy cùng xem các công cụ tạo ra các trình phân tích cú pháp miễn phí.

Antlr

ANTLR là một trình tạo trình phân tích cú pháp tuyệt vời được viết bằng Java, cũng có thể tạo trình phân tích cú pháp cho JavaScript và nhiều ngôn ngữ khác. Ngoài ra còn có phiên bản beta cho TypeScript từ cùng một anh chàng tạo ra phiên bản C# được tối ưu hóa. ANTLR dựa trên thuật toán LL mới được phát triển bởi tác giả và được mô tả trong bài báo này: Phân tích cú pháp LL [*] thích ứng: Sức mạnh của phân tích động [PDF].

Nó khá phổ biến cho nhiều tính năng hữu ích của nó: ví dụ, Phiên bản 4 hỗ trợ các quy tắc hoàn thành bên trái trực tiếp. Tuy nhiên, một giá trị gia tăng thực sự của một cộng đồng rộng lớn, đó là số lượng lớn các ngữ pháp có sẵn.

Nó cung cấp hai cách để đi bộ AST, thay vì nhúng các hành động trong ngữ pháp: khách truy cập và người nghe. Cái đầu tiên phù hợp khi bạn phải thao tác hoặc tương tác với các yếu tố của cây, trong khi thứ hai là hữu ích khi bạn chỉ phải làm điều gì đó khi một quy tắc được khớp.

Ngữ pháp điển hình được chia thành hai phần: quy tắc Lexer và quy tắc phân tích cú pháp. Bộ phận này là ẩn, vì tất cả các quy tắc bắt đầu bằng chữ hoa là các quy tắc của Lexer, trong khi các quy tắc bắt đầu bằng chữ thường là các quy tắc phân tích cú pháp. Ngoài ra, Lexer và trình phân tích cú pháp có thể được xác định trong các tệp riêng biệt.

grammar simple;

basic   : NAME ':' NAME ;

NAME    : [a-zA-Z]* ;

COMMENT : '/*' .*? '*/' -> skip ;

Nếu bạn quan tâm để tìm hiểu cách sử dụng ANTLR, bạn có thể xem xét hướng dẫn antlr khổng lồ này mà chúng tôi đã viết. Nếu bạn đã sẵn sàng để trở thành một nhà phát triển ANTLR chuyên nghiệp, bạn có thể mua khóa học video của chúng tôi để xây dựng các trình phân tích cú pháp và ngôn ngữ chuyên nghiệp bằng cách sử dụng ANTLR. Khóa học được dạy bằng Python, nhưng mã nguồn cũng có sẵn trong JavaScript.Build professional parsers and languages using ANTLR. The course is taught using Python, but the source code is also available in JavaScript.

APG

APG là một trình phân tích cú pháp tái phát đệ quy sử dụng một biến thể của BNF tăng cường, mà họ gọi là BNF tăng cường Superset. ABNF là một biến thể đặc biệt của BNF được thiết kế để hỗ trợ tốt hơn cho giao thức truyền thông hai chiều. APG cũng hỗ trợ các toán tử bổ sung, như các vị từ cú pháp và các chức năng phù hợp với người dùng tùy chỉnh.Augmented BNF, that they call Superset Augmented BNF. ABNF is a particular variant of BNF designed to better support bidirectional communications protocol. APG also support additional operators, like syntactic predicates and custom user defined matching functions.

Nó có thể tạo trình phân tích cú pháp trong C/C ++, Java và JavaScript. Hỗ trợ cho ngôn ngữ cuối cùng có vẻ vượt trội và cập nhật hơn: nó có thêm một vài tính năng và nó được cập nhật gần đây hơn. Trên thực tế, tài liệu cho biết nó được thiết kế để có giao diện của JavaScript Regexp.

Bởi vì nó dựa trên ABNF, nó đặc biệt phù hợp để phân tích các ngôn ngữ của nhiều thông số kỹ thuật internet và trên thực tế, là trình phân tích cú pháp được lựa chọn cho một số công ty viễn thông lớn.

Một ngữ pháp APG rất sạch sẽ và dễ hiểu.

// example from a tutorial of the author of the tool available here
// //www.sitepoint.com/alternative-to-regular-expressions/
phone-number = ["["] area-code sep office-code sep subscriber
area-code    = 3digit                       ; 3 digits
office-code  = 3digit                       ; 3 digits
subscriber   = 4digit                       ; 4 digits
sep          = *3[%d32-47 / %d58-126 / %d9] ; 0-3 ASCII non-digits
digit        = %d48-57                      ; 0-9

Jison

Jison tạo ra các trình phân tích cú pháp từ dưới lên trong JavaScript. API của nó tương tự như Bison, do đó có tên.

Mặc dù tên Jison cũng có thể thay thế Flex, vì vậy bạn không cần một Lexer riêng biệt. Mặc dù bạn có thể sử dụng một hoặc xây dựng Lexer tùy chỉnh của riêng bạn. Tất cả những gì bạn cần là một đối tượng với các chức năng

addition       ::= expression '+' expression
multiplication ::= expression '*' expression
// an expression could be an addition or a multiplication or a number
expression     ::= addition | multiplication |// a number
4 và
addition       ::= expression '+' expression
multiplication ::= expression '*' expression
// an expression could be an addition or a multiplication or a number
expression     ::= addition | multiplication |// a number
5. Nó có thể nhận ra tốt nhất các ngôn ngữ được mô tả bởi LALR [1] ngữ pháp, mặc dù nó cũng có các chế độ cho LR [0], SLR [1].

Trình phân tích cú pháp được tạo không yêu cầu thành phần thời gian chạy, bạn có thể sử dụng nó như một phần mềm độc lập.

Nó có một tài liệu đủ tốt với một vài ví dụ và thậm chí là một phần để thử ngữ pháp của bạn trực tuyến. Mặc dù đôi khi nó dựa vào hướng dẫn sử dụng Bison để bao gồm việc thiếu tài liệu của riêng mình.

Một ngữ pháp jison có thể được nhập bằng định dạng JSON tùy chỉnh hoặc theo phong cách Bison. Cả hai đều yêu cầu bạn sử dụng các hành động nhúng nếu bạn muốn làm điều gì đó khi một quy tắc được khớp. Ví dụ sau là ở định dạng JSON tùy chỉnh.

// example from the documentation
{
   "comment": "JSON Math Parser",
   // JavaScript comments also work

   "lex": {
      "rules": [
         ["s+",                    "/* skip whitespace */"],
         ["[0-9]+[?:.[0-9]+]?b", "return 'NUMBER'"],
         ["*",                     "return '*'"],
         ["/",                     "return '/'"],
         ["-",                       "return '-'"],
         ["+",                     "return '+'"],
         [..] // skipping some parts
      ]
   },

   "operators": [
      ["left", "+", "-"],
      ["left", "*", "/"],
      ["left", "UMINUS"]
      [..] // skipping some parts
   ],

   "bnf": {
      "expressions": [["e EOF",   "return $1"]],

      "e" :[
         ["e + e",  "$$ = $1+$3"],
         ["e - e",  "$$ = $1-$3"],  
         ["- e",    "$$ = -$2", {"prec": "UMINUS"}],         
         ["NUMBER", "$$ = Number[yytext]"],
         [..] // skipping some parts
      ]
   }
}

Nó rất phổ biến và được sử dụng bởi nhiều dự án bao gồm CoffeeScript và tay cầm.js.

Gần

Nearley sử dụng thuật toán phân tích cú pháp Earley được tăng cường với tối ưu hóa Joop Leo, để phân tích các cấu trúc dữ liệu phức tạp một cách dễ dàng. Nearley là über-nhanh và thực sự mạnh mẽ. Nó có thể phân tích bất cứ thứ gì bạn ném vào nó.

Thuật toán Earley được thiết kế để dễ dàng xử lý tất cả các ngữ pháp, bao gồm cả các ngữ pháp được tái sử dụng và mơ hồ. Về cơ bản, lợi thế chính của nó là nó không bao giờ nên thất bại một cách thảm khốc. Mặt khác, nó có thể chậm hơn các thuật toán phân tích cú pháp khác. Gần như bản thân nó cũng có thể phát hiện một số ngữ pháp mơ hồ. Nó cũng có thể và báo cáo nhiều kết quả trong trường hợp đầu vào mơ hồ.

Một ngữ pháp gần là một bản viết trong tệp

addition       ::= expression '+' expression
multiplication ::= expression '*' expression
// an expression could be an addition or a multiplication or a number
expression     ::= addition | multiplication |// a number
6 có thể bao gồm mã tùy chỉnh. Một quy tắc có thể bao gồm một hành động nhúng, mà tài liệu gọi là chức năng hậu xử lý. Bạn cũng có thể sử dụng một Lexer tùy chỉnh.

# from the examples in Nearly
# csv.ne

@{%
var appendItem = function [a, b] { return function [d] { return d[a].concat[[d[b]]]; } };
var appendItemChar = function [a, b] { return function [d] { return d[a].concat[d[b]]; } };
var empty = function [d] { return []; };
var emptyStr = function [d] { return ""; };
%}

file              -> header newline rows             {% function [d] { return { header: d[0], rows: d[2] }; } %}
# id is a special preprocessor function that return the first token in the match
header            -> row                             {% id %}

rows              -> row
                   | rows newline row                {% appendItem[0,2] %}

row               -> field
                   | row "," field                   {% appendItem[0,2] %}

field             -> unquoted_field                  {% id %}
                   | """ quoted_field """          {% function [d] { return d[1]; } %}

quoted_field      -> null                            {% emptyStr %}
                   | quoted_field quoted_field_char  {% appendItemChar[0,1] %}

quoted_field_char -> [^"]                            {% id %}
                   | """ """                       {% function [d] { return """; } %}

unquoted_field    -> null                            {% emptyStr %}
                   | unquoted_field char             {% appendItemChar[0,1] %}

char              -> [^nr",]                       {% id %}

newline           -> "r" "n"                       {% empty %}ca
                   | "r" | "n"                     {% empty %}

Một tính năng thú vị khác là bạn có thể xây dựng mã thông báo tùy chỉnh. Bạn có thể xác định chúng bằng thư viện mã thông báo, hàm theo nghĩa đen hoặc một chức năng kiểm tra. Hàm kiểm tra phải trả về true nếu văn bản tương ứng với mã thông báo cụ thể đó.

@{%
var print_tok  = {literal: "print"};
var number_tok = {test: function[x] {return x.constructor === Number; }}
%}

main -> %print_tok %number_tok

Nearley bao gồm các công cụ để gỡ lỗi và hiểu trình phân tích cú pháp của bạn. Chẳng hạn, Unparser có thể tự động tạo các chuỗi ngẫu nhiên được trình phân tích cú pháp của bạn coi là chính xác. Điều này rất hữu ích để kiểm tra trình phân tích cú pháp của bạn chống lại nhiễu ngẫu nhiên hoặc thậm chí để tạo dữ liệu từ lược đồ [ví dụ: địa chỉ email ngẫu nhiên]. Nó cũng bao gồm một công cụ để tạo sơ đồ đường sắt SVG: một cách đồ họa để đại diện cho một ngữ pháp.

Một trình phân tích cú pháp gần gần yêu cầu thời gian chạy gần.

Tài liệu gần là một cái nhìn tổng quan tốt về những gì có sẵn và cũng có một sân chơi của bên thứ ba để thử một ngữ pháp trực tuyến. Nhưng bạn sẽ không tìm thấy một lời giải thích đầy đủ về tất cả các tính năng.

CỌC

Sau khi trình phân tích cú pháp CFG là thời gian để xem các trình phân tích cú pháp PEG có sẵn cho JavaScript.

Mái hiên

Canopy là một trình biên dịch phân tích cú pháp nhắm mục tiêu Java, JavaScript, Python và Ruby. Nó lấy một tệp mô tả một ngữ pháp biểu thức phân tích cú pháp và biên dịch nó thành một mô -đun phân tích cú pháp trong ngôn ngữ đích. Các trình phân tích cú pháp được tạo không có phụ thuộc thời gian chạy vào chính tán cây.

Nó cũng cung cấp quyền truy cập dễ dàng vào các nút parse cây.

Một ngữ pháp tán có tính năng gọn gàng là sử dụng chú thích hành động để sử dụng mã tùy chỉnh trong trình phân tích cú pháp. Trong điều khoản thực tế. Bạn chỉ cần viết tên của một hàm bên cạnh một quy tắc và sau đó bạn thực hiện hàm trong mã nguồn của mình.

// the actions are prepended by %
grammar Maps
  map     

Bài Viết Liên Quan

Chủ Đề