【问题标题】:Parsing in Emacs Lisp在 Emacs Lisp 中解析
【发布时间】:2010-02-09 11:01:02
【问题描述】:

我正在用 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、string、...)。我想要 价值。因此对于 int 上面的文件,其值为 "1, 2, 3, ...", string “and, or, then, when”和文本“Lorem ...”(不包括破折号)。

我正在考虑两种不同的解决方案,但我不知道该使用哪一种。我应该:

  1. 创建一个简单的解析器,循环遍历所有行并为每个 行将它与一些正则表达式匹配,然后将我想要的部分分组?

  2. 用词法分析器和解析器做一个更复杂的解析器?

现在文件很简单,我想我不需要这样做 像第二种选择一样先进的东西。但是这些文件可能会得到一个 有点复杂,所以我想让它易于扩展。

你会怎么解决这个问题?

【问题讨论】:

  • 看起来您正在重新发明 YAML。
  • 我没有发明任何东西。它们是风站的日志文件。它们看起来确实有点像 YAML。

标签: parsing emacs elisp


【解决方案1】:

您是否已经熟悉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")))))

【讨论】:

  • 我之前找到了递归下降解析器页面。糟糕的是,c-example 并不完整,因此我可以对其进行测试。但我想这是在我的情况下做解析器的好方法。你知道任何 Lisp 例子吗?
  • 恐怕我不知道任何特定的 lisp 示例,但据我所知,示例中缺少的只是标记例程。
  • 几乎不懂任何 c,所以如果示例从头开始工作会好很多。但我会用谷歌搜索其他例子。谢谢!
  • 我在响应中添加了一个玩具 elisp 递归下降解析器。
  • 非常感谢这个例子!不能让它运行:调试器进入--Lisp 错误:(错误类型参数 symbolp(tok(peektok)))
【解决方案2】:

对于解析器的内容,请查看 CEDET 项目中的语义库

【讨论】:

  • 我确实检查过了。不过,这似乎有点矫枉过正。我想学习能够用它做任何有用的事情是很重要的。
  • 如果您认为 CEDET 会变得非常复杂,那么它确实是您的最佳选择。 CEDET 已添加到即将发布的 GNU Emacs 23.2 中,因此它是官方认可的前进方式。这完全取决于语法的复杂程度以及您期望格式扩展的程度。除非你很确定语法不会变得更复杂,否则我可能会选择 CEDET 的语义。
【解决方案3】:

您可以在 Emacs Wiki 上找到一个相对简单的解析器:ParserCompiler

Emacs 的 Parser Compiler 创建 纯递归下降解析器 省略。

该项目的目标是创建一个 有用的解析器编译器 创新和实用。 这是由作者创作的原创作品 Mike Mattie - codermattie@gmail.com

解析器由一个宏编译 将解析器定义 DSL 转换为 纯省略号。语法支持 目前是 PEG 语法课。

【讨论】:

  • 所以如果我使用解析器编译器,我是否必须在我的代码中包含该库?我想避免使用外部库并手动编写解析器。
  • @rejeep 是的,您必须包含该库。
猜你喜欢
  • 2012-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多