2010-02-09 95 views
13

我正在Emacs Lisp中編寫解析器。它是文本文件 尋找這樣的解析器:在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: 
    ... 

我真的不關心鍵(INT,字符串,...)。我想要 值。因此,對於上面的文件int值爲「1,2,3,...」,字符串 「,或者,然後,當」和文本「Lorem ...」(不包括破折號)。

我在考慮兩種不同的解決方案,但我不會使用哪一種解決方案。我應該:

  1. 創建一個簡單的分析程序,通過所有行和每個 線迴路與一些正則表達式匹配,然後組我想出來的零件?

  2. 用詞法分析器和解析器做更復雜的解析器嗎?

眼下文件是非常簡單的,我想我並不需要做什麼 作爲推進作爲第二選擇。但是這些文件可能會更復雜一點,所以我想讓它更容易擴展。

你會如何解決這個問題?

+0

看起來你正在重塑YAML。 – myfreeweb 2010-02-09 11:04:37

+6

我沒有發明任何東西。它們是來自風站的日誌文件。雖然他們看起來有點像YAML。 – rejeep 2010-02-09 11:24:16

回答

5

的解析器的東西看語義庫從CEDET項目

+0

我確實檢查了一下。儘管如此,這似乎相當過分。我想,學習能夠做任何有用的事情都是非常重要的。 – rejeep 2010-02-09 13:03:19

+0

如果您認爲CEDET會變得複雜,CEDET真的是走的路。 CEDET已被添加到即將推出的GNU Emacs 23.2中,所以它是正式批准的方式。這一切都取決於語法的複雜程度以及您期望格式擴展的程度。除非你確定語法不會變得複雜,否則我可能會使用CEDET的語義。 – haxney 2010-02-24 06:27:35

5

有一個相對簡單的解析器,您可以找到在Emacs的維基: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

因此,如果我使用解析器編譯器,是否必須將該庫與我的代碼一起使用?我想避免外部庫並手動編寫解析器。 – rejeep 2010-02-09 19:11:06

+0

@rejeep是的,你將不得不包括圖書館。 – 2010-02-09 19:38:44

13

你已經熟悉了recursive descent parsers?他們使用您最喜愛的編程語言(包括Emacs Lisp)手寫相對容易。對於非常簡單的解析,您可以經常通過looking-atsearch-forward。這些也將構成將由遞歸下降解析器調用的任何tokenizing例程的基礎,或任何其他類型的解析器。

[2009年2月11日]我在下面的emacs lisp中添加了一個遞歸下降解析器的例子。它分析簡單的算術表達式,包括加法,減法,乘法,除法,求冪和帶括號的子表達式。現在,它假定所有令牌都位於全局變量*tokens*中,但如果您根據需要修改gettokpeektok,則可以讓它們遍歷緩衝區。要原樣使用它,請嘗試以下:

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

解析代碼如下。

(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

我發現了遞歸下降解析器頁面。爲了讓這個c-example變得不完整,所以我可以測試它。但我想這是解決我的情況的好辦法。你知道任何Lisp例子嗎? – rejeep 2010-02-09 19:13:20

+0

我不知道任何特定的lisp示例,但是據我所知,這個示例中缺少的是標記化例程。 – 2010-02-09 22:59:16

+0

幾乎不知道任何c,所以如果這個例子是從頭開始的話,它會好很多。但我會爲其他例子谷歌。謝謝! – rejeep 2010-02-10 08:24:39