2010-02-09 56 views
13

Tôi đang viết một trình phân tích cú pháp trong Emacs Lisp. Đó là trình phân tích cú pháp cho các tệp văn bản giống như sau:Phân tích cú pháp trong Emacs Lisp

rule: 
    int: 1, 2, 3, ... 
    string: and, or, then, when 
    text: 
    ---------- 
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Pellentesque 
    in tellus. In pharetra consequat augue. In congue. Curabitur 
    pellentesque iaculis eros. Proin magna odio, posuere sed, commodo nec, 
    varius nec, tortor. 
    ---------- 
    more: ... 

rule: 
    ... 

Tôi không thực sự quan tâm đến khóa (int, string, ...). Tôi muốn giá trị . Vì vậy, đối với tệp int ở trên có giá trị "1, 2, 3, ...", chuỗi "và, hoặc, sau đó, khi" và văn bản "Lorem ..." (không bao gồm dấu gạch ngang).

Tôi đang nghĩ về hai giải pháp khác nhau, nhưng tôi không sử dụng giải pháp nào. Tôi có nên:

  1. tạo ra một phân tích cú pháp đơn giản mà vòng qua tất cả các dòng và mỗi dòng phù hợp nó với một số regex và sau đó nhóm những phần tôi muốn ra ngoài?

  2. thực hiện một trình phân tích cú pháp phức tạp hơn với trình đánh dấu và trình phân tích cú pháp?

Ngay bây giờ các tệp khá đơn giản và tôi đoán tôi không cần phải làm điều gì đó trước như tùy chọn thứ hai. Nhưng những tập tin này có thể nhận được một phức tạp hơn , vì vậy tôi muốn làm cho nó dễ dàng để mở rộng.

Bạn sẽ giải quyết vấn đề này bằng cách nào?

+0

Dường như bạn đang sáng tạo lại YAML. – myfreeweb

+6

Tôi không phát minh ra bất cứ điều gì. Chúng là các tệp nhật ký từ các máy quay gió. Họ trông hơi giống YAML. – rejeep

Trả lời

5

cho các công cụ phân tích cú pháp tìm đến thư viện Semantic từ CEDET dự án

+0

Tôi đã kiểm tra điều đó. Nó có vẻ khá quá mức cần thiết. Tôi đoán nó có nhiều thứ để học để có thể làm bất cứ điều gì hữu ích với nó. – rejeep

+0

CEDET thực sự là con đường để đi nếu bạn nghĩ rằng nó sẽ nhận được ở tất cả các phức tạp. CEDET đã được thêm vào GNU Emacs sắp tới 23.2, do đó, nó là con đường chính thức bị xử phạt về phía trước. Tất cả phụ thuộc vào độ phức tạp của ngữ pháp và bạn mong đợi định dạng mở rộng ra sao.Trừ khi bạn chắc chắn ngữ pháp sẽ không phức tạp hơn nhiều, có lẽ tôi sẽ đi với ngữ nghĩa của CEDET. – haxney

5

Có một phân tích cú pháp tương đối đơn giản, bạn có thể tìm thấy trên Emacs Wiki: ParserCompiler

The Parser Compiler for Emacs creates Recursive Descent parsers in pure elisp.

The goal of the project is to create a useful Parser Compiler that is both innovative and practically useful. This is an original work created by Mike Mattie - [email protected]

Parsers are compiled by a Macro that translates a parser definition DSL to pure elisp. The syntax supports the PEG grammar class currently.

+0

Vì vậy, nếu tôi sử dụng một trình biên dịch phân tích cú pháp, tôi có phải bao gồm thư viện đó với mã của tôi không? Tôi muốn tránh các thư viện bên ngoài và viết phân tích cú pháp bằng tay. – rejeep

+0

@rejeep Có, bạn sẽ phải bao gồm thư viện. –

13

Bạn đã quen thuộc với recursive descent parsers? Chúng tương đối dễ viết bằng ngôn ngữ lập trình yêu thích của bạn, bao gồm Emacs Lisp. Để phân tích cú pháp rất đơn giản, bạn thường có thể nhận được bằng looking-atsearch-forward. Đây cũng sẽ là cơ sở của bất kỳ quy trình tokenizing nào sẽ được gọi bởi trình phân tích cú pháp gốc đệ quy của bạn hoặc bất kỳ kiểu phân tích cú pháp nào khác.

[11 Feb 2009] Tôi đã thêm một trình phân tích cú pháp gốc đệ quy trong các emacs lisp bên dưới. Nó phân tích các biểu thức số học đơn giản bao gồm phép cộng, trừ, nhân, chia, lũy thừa và các biểu thức con được lồng dấu. Ngay bây giờ, nó giả định tất cả các thẻ là trong biến toàn cầu *tokens*, nhưng nếu bạn sửa đổi gettokpeektok khi cần thiết, bạn có thể cho chúng đi qua bộ đệm. Để sử dụng nó như hiện nay, chỉ cần thử các cách sau:

(setq *token* '(3^5^7 + 5 * 3 + 7/11)) 
(rdh/expr) 
=> (+ (+ (^ 3 (^ 5 7)) (* 5 3)) (/ 7 11)) 

Mã phân tích sau.

(defun gettok() 
    (and *token* (pop *token*))) 
(defun peektok() 
    (and *token* (car *token*))) 

(defun rdh/expr() 
    (rdh/expr-tail (rdh/factor))) 

(defun rdh/expr-tail (expr) 
    (let ((tok (peektok))) 
    (cond ((or (null tok) 
      (equal tok ")")) 
     expr) 
     ((member tok '(+ -)) 
     (gettok) 
     (let ((fac (rdh/factor))) 
     (rdh/expr-tail (list tok expr fac)))) 
     (t (error "bad expr"))))) 

(defun rdh/factor() 
    (rdh/factor-tail (rdh/term))) 

(defun rdh/factor-tail (fac) 
    (let ((tok (peektok))) 
    (cond ((or (null tok) 
      (member tok '(")" + -))) 
     fac) 
     ((member tok '(* /)) 
     (gettok) 
     (let ((term (rdh/term))) 
     (rdh/factor-tail (list tok fac term)))) 
     (t (error "bad factor"))))) 

(defun rdh/term() 
    (let* ((prim (rdh/prim)) 
     (tok (peektok))) 
    (cond ((or (null tok) 
       (member tok '(")" + -/*))) 
      prim) 
      ((equal tok '^) 
      (gettok) 
      (list tok prim (rdh/term))) 
      (t (error "bad term"))))) 

(defun rdh/prim() 
    (let ((tok (gettok))) 
    (cond ((numberp tok) tok) 
     ((equal tok "(") 
     (let* ((expr (rdh/expr)) 
      (tok (peektok))) 
     (if (not (equal tok ")")) 
     (error "bad parenthesized expr") 
      (gettok) 
      expr))) 
     (t (error "bad prim"))))) 
+0

Tôi đã tìm thấy trang phân tích cú pháp gốc đệ quy trước đó. Để xấu c-ví dụ đã không được hoàn thành để tôi có thể kiểm tra nó mặc dù. Nhưng tôi đoán đây là một cách tốt để làm phân tích cú pháp trong trường hợp của tôi. Bạn có biết về bất kỳ ví dụ Lisp nào không? – rejeep

+0

Tôi không biết bất kỳ ví dụ cụ thể nào lisp, tôi sợ, nhưng theo như tôi có thể nói tất cả những gì còn thiếu trong ví dụ này là thói quen thông báo. –

+0

Không biết gần như bất kỳ c, vì vậy nó sẽ tốt hơn rất nhiều nếu ví dụ đã được làm việc từ đầu. Nhưng tôi sẽ google cho các ví dụ khác. Cảm ơn! – rejeep

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