Анализ в 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, string,...). Я хочу стоимость. Итак, для файла выше int имеет значение "1, 2, 3,...", строка "и, или тогда, когда" и текст "Lorem..." (исключая тире).

Я думаю о двух разных решениях, но я не использую их. Должен ли я:

  • создать простой синтаксический анализатор, проходящий через все строки и для каждого строка соответствует ему с некоторым регулярным выражением, а затем группирует части, которые я хочу получить?

  • Сделайте более сложный парсер с лексером и парсером?

Сейчас файлы довольно просты, и я думаю, мне не нужно делать что-то как продвижение, как второй вариант. Но эти файлы могут получить бит более сложный, поэтому я хочу упростить его расширение.

Как бы вы решили это?

Ответы

Ответ 1

Вы уже знакомы с рекурсивными анализаторами спуска? Их относительно легко написать вручную на вашем любимом языке программирования, который будет включать Emacs Lisp. Для очень простого синтаксического анализа вы часто можете использовать looking-at и search-forward. Они также легли бы в основу любой токенизации подпрограмм, которые будут вызываться парсером рекурсивного спуска или любым другим стилем парсера.

[11 февраля 2009] Я добавил пример рекурсивного парсера спуска в emacs lisp ниже. Он анализирует простые арифметические выражения, включая сложение, вычитание, умножение, деление, возведение в степень и выраженные в скобках подвыражения. В настоящий момент предполагается, что все токены находятся в глобальной переменной *tokens*, но если вы измените gettok и peektok по мере необходимости, вы можете пройти через буфер. Чтобы использовать его как есть, просто попробуйте следующее:

(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")))))

Ответ 2

для парсерного материала посмотрите на семантическую библиотеку CEDET project

Ответ 3

В Emacs Wiki существует относительно простой синтаксический анализатор: ParserCompiler

Компилятор Parser для Emacs создает Анализаторы рекурсивного спуска в чистом виде Elisp.

Цель проекта - создать полезный компилятор Parser, который является одновременно инновационным и практически полезным. Это оригинальная работа, созданная Майк Мэтти - [email protected]

Парсеры скомпилированы макросом, который преобразует определение парсера DSL в чистый элипс. Синтаксис поддерживает PEG в настоящее время.